From 7758592a653aa6e8033300f97e72d53c279a9277 Mon Sep 17 00:00:00 2001
From: zeke <40004347+KAJdev@users.noreply.github.com>
Date: Thu, 8 Aug 2024 16:22:26 -0800
Subject: [PATCH 1/4] feat: navbar redesign
---
docusaurus.config.js | 13 +++-
package.json | 1 +
src/css/custom.css | 50 +++++++++++---
src/theme/Layout.js | 21 ++++++
src/theme/Logo/index.js | 65 ++++++++++++++++++
src/theme/Navbar/Content/index.js | 77 ++++++++++++++++++++++
src/theme/Navbar/Content/styles.module.css | 8 +++
src/theme/Navbar/Search/index.js | 10 +++
src/theme/Navbar/Search/styles.module.css | 18 +++++
src/theme/NavbarItem/SearchNavbarItem.js | 13 ++++
10 files changed, 264 insertions(+), 12 deletions(-)
create mode 100644 src/theme/Layout.js
create mode 100644 src/theme/Logo/index.js
create mode 100644 src/theme/Navbar/Content/index.js
create mode 100644 src/theme/Navbar/Content/styles.module.css
create mode 100644 src/theme/Navbar/Search/index.js
create mode 100644 src/theme/Navbar/Search/styles.module.css
create mode 100644 src/theme/NavbarItem/SearchNavbarItem.js
diff --git a/docusaurus.config.js b/docusaurus.config.js
index b3e088a..d70d2e3 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -14,7 +14,8 @@ import { themes as prismThemes } from "prism-react-renderer";
/** @type {import('@docusaurus/types').Config} */
const config = {
title: "RunPod Documentation",
- tagline: "Globally distributed GPU cloud built for production. Develop, train, and scale AI applications.",
+ tagline:
+ "Globally distributed GPU cloud built for production. Develop, train, and scale AI applications.",
favicon: "img/favicon.ico",
url: "https://docs.runpod.io",
baseUrl: "/",
@@ -105,6 +106,7 @@ const config = {
logo: {
alt: "RunPod Logo",
src: "img/logo.svg",
+ target: "_self",
},
items: [
{
@@ -123,7 +125,11 @@ const config = {
},
{ href: "https://blog.runpod.io", label: "Blog", position: "left" },
- { href: "https://www.runpod.io/console/signup", label: "Sign up", position: "left" },
+ {
+ href: "https://www.runpod.io/console/signup",
+ label: "Sign up",
+ position: "left",
+ },
{
href: "https://github.com/runpod",
label: "GitHub",
@@ -214,7 +220,8 @@ const config = {
"data-website-id": "d8e25089-cadd-4c1c-9010-7e83cd99a2a5",
"data-project-name": "RunPod",
"data-project-color": "#070D27",
- "data-project-logo": "https://avatars.githubusercontent.com/u/95939477?s=200&v=4",
+ "data-project-logo":
+ "https://avatars.githubusercontent.com/u/95939477?s=200&v=4",
async: true,
},
{
diff --git a/package.json b/package.json
index 92ff599..349aba2 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
+ "dev": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
diff --git a/src/css/custom.css b/src/css/custom.css
index 00d6161..77e419a 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -15,16 +15,48 @@
--ifm-color-primary-lightest: #a87deb; /* Lightest tint */
--ifm-code-font-size: 95%; /* Adjusted code font size */
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); /* Highlighted code line background in light mode */
+ --ifm-font-family-base: 'Inter', sans-serif; /* Base font family */
+ font-family: var(--ifm-font-family-base) !important;
}
/* For readability concerns, you should choose a lighter palette in dark mode. */
-[data-theme='dark'] {
- --ifm-color-primary: #a382ec; /* Primary color for dark mode */
- --ifm-color-primary-dark: #9775e3; /* Dark shade for dark mode */
- --ifm-color-primary-darker: #8c68db; /* Darker shade for dark mode */
- --ifm-color-primary-darkest: #7a59c9; /* Darkest shade for dark mode */
- --ifm-color-primary-light: #ab8eed; /* Light tint for dark mode */
- --ifm-color-primary-lighter: #b39bf0; /* Lighter tint for dark mode */
- --ifm-color-primary-lightest: #beb0f3; /* Lightest tint for dark mode */
- --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); /* Highlighted code line background in dark mode */
+/* dark mode */
+[data-theme='dark']:root {
+ --ifm-color-primary: #a382ec; /* Primary color for dark mode */
+ --ifm-color-primary-dark: #9775e3; /* Dark shade for dark mode */
+ --ifm-color-primary-darker: #8c68db; /* Darker shade for dark mode */
+ --ifm-color-primary-darkest: #7a59c9; /* Darkest shade for dark mode */
+ --ifm-color-primary-light: #ab8eed; /* Light tint for dark mode */
+ --ifm-color-primary-lighter: #b39bf0; /* Lighter tint for dark mode */
+ --ifm-color-primary-lightest: #beb0f3; /* Lightest tint for dark mode */
+ --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); /* Highlighted code line background in dark mode */
+ --ifm-navbar-background-color: #000;
}
+
+body {
+ font-family: var(--ifm-font-family-base) !important;
+}
+
+.navbar--fixed-top {
+ padding-left: 36px;
+ padding-right: 36px;
+ border-bottom: 1px solid var(--ifm-toc-border-color);
+ box-shadow: none;
+ font-size: 14px;
+ font-family: "Inter", sans-serif;
+}
+
+.navbar__brand:has(.navbar__title) {
+ margin-left: 30px;
+}
+
+.navbar__items {
+ --ifm-navbar-item-padding-horizontal: 20px;
+}
+
+@media (max-width: 768px) {
+ .navbar--fixed-top {
+ padding-left: 25px;
+ padding-right: 20px;
+ }
+}
\ No newline at end of file
diff --git a/src/theme/Layout.js b/src/theme/Layout.js
new file mode 100644
index 0000000..cd22fa8
--- /dev/null
+++ b/src/theme/Layout.js
@@ -0,0 +1,21 @@
+import React from "react";
+import OriginalLayout from "@theme-original/Layout";
+import Head from "@docusaurus/Head";
+import { useLocation } from "@docusaurus/router";
+
+export default function Layout(props) {
+ const location = useLocation();
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/theme/Logo/index.js b/src/theme/Logo/index.js
new file mode 100644
index 0000000..631c210
--- /dev/null
+++ b/src/theme/Logo/index.js
@@ -0,0 +1,65 @@
+import React from "react";
+import Link from "@docusaurus/Link";
+import useBaseUrl from "@docusaurus/useBaseUrl";
+import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import { useThemeConfig } from "@docusaurus/theme-common";
+import ThemedImage from "@theme/ThemedImage";
+function LogoThemedImage({ logo, alt, imageClassName }) {
+ const sources = {
+ light: useBaseUrl(logo.src),
+ dark: useBaseUrl(logo.srcDark || logo.src),
+ };
+ const themedImage = (
+
+ );
+ // Is this extra div really necessary?
+ // introduced in https://github.com/facebook/docusaurus/pull/5666
+ return imageClassName ? (
+ {themedImage}
+ ) : (
+ themedImage
+ );
+}
+export default function Logo(props) {
+ const {
+ siteConfig: { title },
+ } = useDocusaurusContext();
+ const {
+ navbar: { title: navbarTitle, logo },
+ } = useThemeConfig();
+ const { imageClassName, titleClassName, ...propsRest } = props;
+ const logoLink = useBaseUrl(logo?.href || "/");
+ // If visible title is shown, fallback alt text should be
+ // an empty string to mark the logo as decorative.
+ const fallbackAlt = navbarTitle ? "" : title;
+ // Use logo alt text if provided (including empty string),
+ // and provide a sensible fallback otherwise.
+ const alt = logo?.alt ?? fallbackAlt;
+ return (
+ <>
+ {logo && (
+
+
+
+ )}
+
+ {navbarTitle != null && {navbarTitle}}
+
+ >
+ );
+}
diff --git a/src/theme/Navbar/Content/index.js b/src/theme/Navbar/Content/index.js
new file mode 100644
index 0000000..122e2fb
--- /dev/null
+++ b/src/theme/Navbar/Content/index.js
@@ -0,0 +1,77 @@
+import React from "react";
+import { useThemeConfig, ErrorCauseBoundary } from "@docusaurus/theme-common";
+import {
+ splitNavbarItems,
+ useNavbarMobileSidebar,
+} from "@docusaurus/theme-common/internal";
+import NavbarItem from "@theme/NavbarItem";
+import NavbarColorModeToggle from "@theme/Navbar/ColorModeToggle";
+import SearchBar from "@theme/SearchBar";
+import NavbarMobileSidebarToggle from "@theme/Navbar/MobileSidebar/Toggle";
+import NavbarLogo from "@theme/Navbar/Logo";
+import NavbarSearch from "@theme/Navbar/Search";
+import styles from "./styles.module.css";
+function useNavbarItems() {
+ // TODO temporary casting until ThemeConfig type is improved
+ return useThemeConfig().navbar.items;
+}
+function NavbarItems({ items }) {
+ return (
+ <>
+ {items.map((item, i) => (
+
+ new Error(
+ `A theme navbar item failed to render.
+Please double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:
+${JSON.stringify(item, null, 2)}`,
+ { cause: error }
+ )
+ }
+ >
+
+
+ ))}
+ >
+ );
+}
+function NavbarContentLayout({ left, right }) {
+ return (
+
+ );
+}
+export default function NavbarContent() {
+ const mobileSidebar = useNavbarMobileSidebar();
+ const items = useNavbarItems();
+ const [leftItems, rightItems] = splitNavbarItems(items);
+ const searchBarItem = items.find((item) => item.type === "search");
+ return (
+
+
+
+ >
+ }
+ right={
+ // TODO stop hardcoding items?
+ // Ask the user to add the respective navbar items => more flexible
+ <>
+
+
+ {!searchBarItem && (
+
+
+
+ )}
+ {!mobileSidebar.disabled && }
+ >
+ }
+ />
+ );
+}
diff --git a/src/theme/Navbar/Content/styles.module.css b/src/theme/Navbar/Content/styles.module.css
new file mode 100644
index 0000000..b4bda8c
--- /dev/null
+++ b/src/theme/Navbar/Content/styles.module.css
@@ -0,0 +1,8 @@
+/*
+Hide color mode toggle in small viewports
+ */
+@media (max-width: 768px) {
+ .colorModeToggle {
+ display: none;
+ }
+}
diff --git a/src/theme/Navbar/Search/index.js b/src/theme/Navbar/Search/index.js
new file mode 100644
index 0000000..686f73b
--- /dev/null
+++ b/src/theme/Navbar/Search/index.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import clsx from 'clsx';
+import styles from './styles.module.css';
+export default function NavbarSearch({children, className}) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/theme/Navbar/Search/styles.module.css b/src/theme/Navbar/Search/styles.module.css
new file mode 100644
index 0000000..f1a731c
--- /dev/null
+++ b/src/theme/Navbar/Search/styles.module.css
@@ -0,0 +1,18 @@
+/*
+Workaround to avoid rendering empty search container
+See https://github.com/facebook/docusaurus/pull/9385
+*/
+.navbarSearchContainer:empty {
+ display: none;
+}
+
+@media (max-width: 996px) {
+ .navbarSearchContainer {
+ position: relative;
+ margin-right: 20px;
+ }
+}
+
+.navbarSearchContainer {
+ margin-left: 20px;
+}
\ No newline at end of file
diff --git a/src/theme/NavbarItem/SearchNavbarItem.js b/src/theme/NavbarItem/SearchNavbarItem.js
new file mode 100644
index 0000000..9cf4462
--- /dev/null
+++ b/src/theme/NavbarItem/SearchNavbarItem.js
@@ -0,0 +1,13 @@
+import React from 'react';
+import SearchBar from '@theme/SearchBar';
+import NavbarSearch from '@theme/Navbar/Search';
+export default function SearchNavbarItem({mobile, className}) {
+ if (mobile) {
+ return null;
+ }
+ return (
+
+
+
+ );
+}
From 04b9006a89b2226e7b84bc6aaf90f81ca566b3bb Mon Sep 17 00:00:00 2001
From: zeke <40004347+KAJdev@users.noreply.github.com>
Date: Thu, 8 Aug 2024 16:26:10 -0800
Subject: [PATCH 2/4] fix
---
src/theme/Logo/index.js | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/theme/Logo/index.js b/src/theme/Logo/index.js
index 631c210..9507440 100644
--- a/src/theme/Logo/index.js
+++ b/src/theme/Logo/index.js
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useLayoutEffect } from "react";
import Link from "@docusaurus/Link";
import useBaseUrl from "@docusaurus/useBaseUrl";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
@@ -27,6 +27,7 @@ function LogoThemedImage({ logo, alt, imageClassName }) {
themedImage
);
}
+
export default function Logo(props) {
const {
siteConfig: { title },
@@ -35,18 +36,23 @@ export default function Logo(props) {
navbar: { title: navbarTitle, logo },
} = useThemeConfig();
const { imageClassName, titleClassName, ...propsRest } = props;
- const logoLink = useBaseUrl(logo?.href || "/");
// If visible title is shown, fallback alt text should be
// an empty string to mark the logo as decorative.
const fallbackAlt = navbarTitle ? "" : title;
// Use logo alt text if provided (including empty string),
// and provide a sensible fallback otherwise.
const alt = logo?.alt ?? fallbackAlt;
+
+ const [logoLink, setLogoLink] = React.useState(logo?.href || "/");
+ useLayoutEffect(() => {
+ setLogoLink(window.location.origin);
+ }, []);
+
return (
<>
{logo && (
From 9ca0582137ecc88da3525ffad56d33c6d22b64f7 Mon Sep 17 00:00:00 2001
From: zeke <40004347+KAJdev@users.noreply.github.com>
Date: Mon, 12 Aug 2024 18:41:51 -0800
Subject: [PATCH 3/4] update logo, better responsiveness, bigger text
---
docusaurus.config.js | 6 +-
src/css/custom.css | 18 +-
src/pages/index.module.css | 2 +-
.../Navbar/MobileSidebar/Toggle/index.tsx | 23 +++
src/theme/NavbarItem/ComponentTypes.tsx | 25 +++
src/theme/NavbarItem/DefaultNavbarItem.tsx | 59 ++++++
src/theme/NavbarItem/DocNavbarItem.tsx | 34 ++++
src/theme/NavbarItem/DocSidebarNavbarItem.tsx | 29 +++
.../DocsVersionDropdownNavbarItem.tsx | 92 +++++++++
.../NavbarItem/DocsVersionNavbarItem.tsx | 20 ++
.../NavbarItem/DropdownNavbarItem/index.tsx | 176 ++++++++++++++++++
.../DropdownNavbarItem/styles.module.css | 3 +
src/theme/NavbarItem/HtmlNavbarItem.tsx | 25 +++
.../LocaleDropdownNavbarItem/index.tsx | 76 ++++++++
.../styles.module.css | 4 +
src/theme/NavbarItem/NavbarNavLink.tsx | 67 +++++++
src/theme/NavbarItem/SearchNavbarItem.tsx | 19 ++
src/theme/NavbarItem/index.tsx | 21 +++
static/img/icon.svg | 4 +
static/img/logoDarkMode.svg | 5 +
static/img/logoLightMode.svg | 5 +
21 files changed, 707 insertions(+), 6 deletions(-)
create mode 100644 src/theme/Navbar/MobileSidebar/Toggle/index.tsx
create mode 100644 src/theme/NavbarItem/ComponentTypes.tsx
create mode 100644 src/theme/NavbarItem/DefaultNavbarItem.tsx
create mode 100644 src/theme/NavbarItem/DocNavbarItem.tsx
create mode 100644 src/theme/NavbarItem/DocSidebarNavbarItem.tsx
create mode 100644 src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
create mode 100644 src/theme/NavbarItem/DocsVersionNavbarItem.tsx
create mode 100644 src/theme/NavbarItem/DropdownNavbarItem/index.tsx
create mode 100644 src/theme/NavbarItem/DropdownNavbarItem/styles.module.css
create mode 100644 src/theme/NavbarItem/HtmlNavbarItem.tsx
create mode 100644 src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx
create mode 100644 src/theme/NavbarItem/LocaleDropdownNavbarItem/styles.module.css
create mode 100644 src/theme/NavbarItem/NavbarNavLink.tsx
create mode 100644 src/theme/NavbarItem/SearchNavbarItem.tsx
create mode 100644 src/theme/NavbarItem/index.tsx
create mode 100644 static/img/icon.svg
create mode 100644 static/img/logoDarkMode.svg
create mode 100644 static/img/logoLightMode.svg
diff --git a/docusaurus.config.js b/docusaurus.config.js
index d70d2e3..657534c 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -101,12 +101,14 @@ const config = {
},
image: "img/docusaurus-social-card.png",
navbar: {
- title: "RunPod",
+ title: "Docs Home",
logo: {
alt: "RunPod Logo",
- src: "img/logo.svg",
+ src: "img/logoLightMode.svg",
+ srcDark: "img/logoDarkMode.svg",
target: "_self",
+ href: "https://www.runpod.io",
},
items: [
{
diff --git a/src/css/custom.css b/src/css/custom.css
index 77e419a..f0bbc7a 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -42,7 +42,7 @@ body {
padding-right: 36px;
border-bottom: 1px solid var(--ifm-toc-border-color);
box-shadow: none;
- font-size: 14px;
+ font-size: 16px;
font-family: "Inter", sans-serif;
}
@@ -54,9 +54,21 @@ body {
--ifm-navbar-item-padding-horizontal: 20px;
}
-@media (max-width: 768px) {
+@media (max-width: 1200px) {
.navbar--fixed-top {
- padding-left: 25px;
+ padding-left: 15px;
padding-right: 20px;
}
+}
+
+@media screen and (max-width: 1199px) {
+ a[href*="github.com"] {
+ display: none;
+ }
+}
+
+@media screen and (min-width: 1200px) {
+ a[href*="github.com"] {
+ display: inline; /* or whatever display property you want */
+ }
}
\ No newline at end of file
diff --git a/src/pages/index.module.css b/src/pages/index.module.css
index fbe0a52..ff20137 100644
--- a/src/pages/index.module.css
+++ b/src/pages/index.module.css
@@ -1,6 +1,6 @@
/* General Styles */
body {
- font-family: 'Arial', sans-serif;
+ font-family: 'Inter', sans-serif;
margin: 0;
}
diff --git a/src/theme/Navbar/MobileSidebar/Toggle/index.tsx b/src/theme/Navbar/MobileSidebar/Toggle/index.tsx
new file mode 100644
index 0000000..9691f10
--- /dev/null
+++ b/src/theme/Navbar/MobileSidebar/Toggle/index.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal';
+import {translate} from '@docusaurus/Translate';
+import IconMenu from '@theme/Icon/Menu';
+
+export default function MobileSidebarToggle(): JSX.Element {
+ const {toggle, shown} = useNavbarMobileSidebar();
+ return (
+
+ );
+}
diff --git a/src/theme/NavbarItem/ComponentTypes.tsx b/src/theme/NavbarItem/ComponentTypes.tsx
new file mode 100644
index 0000000..df6a5f2
--- /dev/null
+++ b/src/theme/NavbarItem/ComponentTypes.tsx
@@ -0,0 +1,25 @@
+import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
+import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
+import LocaleDropdownNavbarItem from '@theme/NavbarItem/LocaleDropdownNavbarItem';
+import SearchNavbarItem from '@theme/NavbarItem/SearchNavbarItem';
+import HtmlNavbarItem from '@theme/NavbarItem/HtmlNavbarItem';
+import DocNavbarItem from '@theme/NavbarItem/DocNavbarItem';
+import DocSidebarNavbarItem from '@theme/NavbarItem/DocSidebarNavbarItem';
+import DocsVersionNavbarItem from '@theme/NavbarItem/DocsVersionNavbarItem';
+import DocsVersionDropdownNavbarItem from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
+
+import type {ComponentTypesObject} from '@theme/NavbarItem/ComponentTypes';
+
+const ComponentTypes: ComponentTypesObject = {
+ default: DefaultNavbarItem,
+ localeDropdown: LocaleDropdownNavbarItem,
+ search: SearchNavbarItem,
+ dropdown: DropdownNavbarItem,
+ html: HtmlNavbarItem,
+ doc: DocNavbarItem,
+ docSidebar: DocSidebarNavbarItem,
+ docsVersion: DocsVersionNavbarItem,
+ docsVersionDropdown: DocsVersionDropdownNavbarItem,
+};
+
+export default ComponentTypes;
diff --git a/src/theme/NavbarItem/DefaultNavbarItem.tsx b/src/theme/NavbarItem/DefaultNavbarItem.tsx
new file mode 100644
index 0000000..b63d971
--- /dev/null
+++ b/src/theme/NavbarItem/DefaultNavbarItem.tsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import clsx from 'clsx';
+import NavbarNavLink from '@theme/NavbarItem/NavbarNavLink';
+import type {
+ DesktopOrMobileNavBarItemProps,
+ Props,
+} from '@theme/NavbarItem/DefaultNavbarItem';
+
+function DefaultNavbarItemDesktop({
+ className,
+ isDropdownItem = false,
+ ...props
+}: DesktopOrMobileNavBarItemProps) {
+ const element = (
+
+ );
+
+ if (isDropdownItem) {
+ return {element};
+ }
+
+ return element;
+}
+
+function DefaultNavbarItemMobile({
+ className,
+ isDropdownItem,
+ ...props
+}: DesktopOrMobileNavBarItemProps) {
+ return (
+
+
+
+ );
+}
+
+export default function DefaultNavbarItem({
+ mobile = false,
+ position, // Need to destructure position from props so that it doesn't get passed on.
+ ...props
+}: Props): JSX.Element {
+ const Comp = mobile ? DefaultNavbarItemMobile : DefaultNavbarItemDesktop;
+ return (
+
+ );
+}
diff --git a/src/theme/NavbarItem/DocNavbarItem.tsx b/src/theme/NavbarItem/DocNavbarItem.tsx
new file mode 100644
index 0000000..f391a21
--- /dev/null
+++ b/src/theme/NavbarItem/DocNavbarItem.tsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import {useActiveDocContext} from '@docusaurus/plugin-content-docs/client';
+import {useLayoutDoc} from '@docusaurus/theme-common/internal';
+import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
+import type {Props} from '@theme/NavbarItem/DocNavbarItem';
+
+export default function DocNavbarItem({
+ docId,
+ label: staticLabel,
+ docsPluginId,
+ ...props
+}: Props): JSX.Element | null {
+ const {activeDoc} = useActiveDocContext(docsPluginId);
+ const doc = useLayoutDoc(docId, docsPluginId);
+ const pageActive = activeDoc?.path === doc?.path;
+
+ // Draft and unlisted items are not displayed in the navbar.
+ if (doc === null || (doc.unlisted && !pageActive)) {
+ return null;
+ }
+
+ return (
+
+ pageActive ||
+ (!!activeDoc?.sidebar && activeDoc.sidebar === doc.sidebar)
+ }
+ label={staticLabel ?? doc.id}
+ to={doc.path}
+ />
+ );
+}
diff --git a/src/theme/NavbarItem/DocSidebarNavbarItem.tsx b/src/theme/NavbarItem/DocSidebarNavbarItem.tsx
new file mode 100644
index 0000000..4c8245a
--- /dev/null
+++ b/src/theme/NavbarItem/DocSidebarNavbarItem.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import {useActiveDocContext} from '@docusaurus/plugin-content-docs/client';
+import {useLayoutDocsSidebar} from '@docusaurus/theme-common/internal';
+import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
+import type {Props} from '@theme/NavbarItem/DocSidebarNavbarItem';
+
+export default function DocSidebarNavbarItem({
+ sidebarId,
+ label,
+ docsPluginId,
+ ...props
+}: Props): JSX.Element {
+ const {activeDoc} = useActiveDocContext(docsPluginId);
+ const sidebarLink = useLayoutDocsSidebar(sidebarId, docsPluginId).link;
+ if (!sidebarLink) {
+ throw new Error(
+ `DocSidebarNavbarItem: Sidebar with ID "${sidebarId}" doesn't have anything to be linked to.`,
+ );
+ }
+ return (
+ activeDoc?.sidebar === sidebarId}
+ label={label ?? sidebarLink.label}
+ to={sidebarLink.path}
+ />
+ );
+}
diff --git a/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx b/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
new file mode 100644
index 0000000..819223c
--- /dev/null
+++ b/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
@@ -0,0 +1,92 @@
+import React from 'react';
+import {
+ useVersions,
+ useActiveDocContext,
+} from '@docusaurus/plugin-content-docs/client';
+import {useDocsPreferredVersion} from '@docusaurus/theme-common';
+import {useDocsVersionCandidates} from '@docusaurus/theme-common/internal';
+import {translate} from '@docusaurus/Translate';
+import {useLocation} from '@docusaurus/router';
+import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
+import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
+import type {Props} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
+import type {GlobalVersion} from '@docusaurus/plugin-content-docs/client';
+
+const getVersionMainDoc = (version: GlobalVersion) =>
+ version.docs.find((doc) => doc.id === version.mainDocId)!;
+
+export default function DocsVersionDropdownNavbarItem({
+ mobile,
+ docsPluginId,
+ dropdownActiveClassDisabled,
+ dropdownItemsBefore,
+ dropdownItemsAfter,
+ ...props
+}: Props): JSX.Element {
+ const {search, hash} = useLocation();
+ const activeDocContext = useActiveDocContext(docsPluginId);
+ const versions = useVersions(docsPluginId);
+ const {savePreferredVersionName} = useDocsPreferredVersion(docsPluginId);
+ const versionLinks = versions.map((version) => {
+ // We try to link to the same doc, in another version
+ // When not possible, fallback to the "main doc" of the version
+ const versionDoc =
+ activeDocContext.alternateDocVersions[version.name] ??
+ getVersionMainDoc(version);
+ return {
+ label: version.label,
+ // preserve ?search#hash suffix on version switches
+ to: `${versionDoc.path}${search}${hash}`,
+ isActive: () => version === activeDocContext.activeVersion,
+ onClick: () => savePreferredVersionName(version.name),
+ };
+ });
+ const items = [
+ ...dropdownItemsBefore,
+ ...versionLinks,
+ ...dropdownItemsAfter,
+ ];
+
+ const dropdownVersion = useDocsVersionCandidates(docsPluginId)[0];
+
+ // Mobile dropdown is handled a bit differently
+ const dropdownLabel =
+ mobile && items.length > 1
+ ? translate({
+ id: 'theme.navbar.mobileVersionsDropdown.label',
+ message: 'Versions',
+ description:
+ 'The label for the navbar versions dropdown on mobile view',
+ })
+ : dropdownVersion.label;
+ const dropdownTo =
+ mobile && items.length > 1
+ ? undefined
+ : getVersionMainDoc(dropdownVersion).path;
+
+ // We don't want to render a version dropdown with 0 or 1 item. If we build
+ // the site with a single docs version (onlyIncludeVersions: ['1.0.0']),
+ // We'd rather render a button instead of a dropdown
+ if (items.length <= 1) {
+ return (
+ false : undefined}
+ />
+ );
+ }
+
+ return (
+ false : undefined}
+ />
+ );
+}
diff --git a/src/theme/NavbarItem/DocsVersionNavbarItem.tsx b/src/theme/NavbarItem/DocsVersionNavbarItem.tsx
new file mode 100644
index 0000000..13cd570
--- /dev/null
+++ b/src/theme/NavbarItem/DocsVersionNavbarItem.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import {useDocsVersionCandidates} from '@docusaurus/theme-common/internal';
+import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
+import type {Props} from '@theme/NavbarItem/DocsVersionNavbarItem';
+import type {GlobalVersion} from '@docusaurus/plugin-content-docs/client';
+
+const getVersionMainDoc = (version: GlobalVersion) =>
+ version.docs.find((doc) => doc.id === version.mainDocId)!;
+
+export default function DocsVersionNavbarItem({
+ label: staticLabel,
+ to: staticTo,
+ docsPluginId,
+ ...props
+}: Props): JSX.Element {
+ const version = useDocsVersionCandidates(docsPluginId)[0];
+ const label = staticLabel ?? version.label;
+ const path = staticTo ?? getVersionMainDoc(version).path;
+ return ;
+}
diff --git a/src/theme/NavbarItem/DropdownNavbarItem/index.tsx b/src/theme/NavbarItem/DropdownNavbarItem/index.tsx
new file mode 100644
index 0000000..faf2513
--- /dev/null
+++ b/src/theme/NavbarItem/DropdownNavbarItem/index.tsx
@@ -0,0 +1,176 @@
+import React, {useState, useRef, useEffect} from 'react';
+import clsx from 'clsx';
+import {
+ isRegexpStringMatch,
+ useCollapsible,
+ Collapsible,
+} from '@docusaurus/theme-common';
+import {isSamePath, useLocalPathname} from '@docusaurus/theme-common/internal';
+import NavbarNavLink from '@theme/NavbarItem/NavbarNavLink';
+import NavbarItem, {type LinkLikeNavbarItemProps} from '@theme/NavbarItem';
+import type {
+ DesktopOrMobileNavBarItemProps,
+ Props,
+} from '@theme/NavbarItem/DropdownNavbarItem';
+import styles from './styles.module.css';
+
+function isItemActive(
+ item: LinkLikeNavbarItemProps,
+ localPathname: string,
+): boolean {
+ if (isSamePath(item.to, localPathname)) {
+ return true;
+ }
+ if (isRegexpStringMatch(item.activeBaseRegex, localPathname)) {
+ return true;
+ }
+ if (item.activeBasePath && localPathname.startsWith(item.activeBasePath)) {
+ return true;
+ }
+ return false;
+}
+
+function containsActiveItems(
+ items: readonly LinkLikeNavbarItemProps[],
+ localPathname: string,
+): boolean {
+ return items.some((item) => isItemActive(item, localPathname));
+}
+
+function DropdownNavbarItemDesktop({
+ items,
+ position,
+ className,
+ onClick,
+ ...props
+}: DesktopOrMobileNavBarItemProps) {
+ const dropdownRef = useRef(null);
+ const [showDropdown, setShowDropdown] = useState(false);
+
+ useEffect(() => {
+ const handleClickOutside = (
+ event: MouseEvent | TouchEvent | FocusEvent,
+ ) => {
+ if (
+ !dropdownRef.current ||
+ dropdownRef.current.contains(event.target as Node)
+ ) {
+ return;
+ }
+ setShowDropdown(false);
+ };
+
+ document.addEventListener('mousedown', handleClickOutside);
+ document.addEventListener('touchstart', handleClickOutside);
+ document.addEventListener('focusin', handleClickOutside);
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ document.removeEventListener('touchstart', handleClickOutside);
+ document.removeEventListener('focusin', handleClickOutside);
+ };
+ }, [dropdownRef]);
+
+ return (
+
+
tag focusable in case no link target
+ // See https://github.com/facebook/docusaurus/pull/6003
+ // There's probably a better solution though...
+ href={props.to ? undefined : '#'}
+ className={clsx('navbar__link', className)}
+ {...props}
+ onClick={props.to ? undefined : (e) => e.preventDefault()}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ setShowDropdown(!showDropdown);
+ }
+ }}>
+ {props.children ?? props.label}
+
+
+ {items.map((childItemProps, i) => (
+
+ ))}
+
+
+ );
+}
+
+function DropdownNavbarItemMobile({
+ items,
+ className,
+ position, // Need to destructure position from props so that it doesn't get passed on.
+ onClick,
+ ...props
+}: DesktopOrMobileNavBarItemProps) {
+ const localPathname = useLocalPathname();
+ const containsActive = containsActiveItems(items, localPathname);
+
+ const {collapsed, toggleCollapsed, setCollapsed} = useCollapsible({
+ initialState: () => !containsActive,
+ });
+
+ // Expand/collapse if any item active after a navigation
+ useEffect(() => {
+ if (containsActive) {
+ setCollapsed(!containsActive);
+ }
+ }, [localPathname, containsActive, setCollapsed]);
+
+ return (
+
+ {
+ e.preventDefault();
+ toggleCollapsed();
+ }}>
+ {props.children ?? props.label}
+
+
+ {items.map((childItemProps, i) => (
+
+ ))}
+
+
+ );
+}
+
+export default function DropdownNavbarItem({
+ mobile = false,
+ ...props
+}: Props): JSX.Element {
+ const Comp = mobile ? DropdownNavbarItemMobile : DropdownNavbarItemDesktop;
+ return ;
+}
diff --git a/src/theme/NavbarItem/DropdownNavbarItem/styles.module.css b/src/theme/NavbarItem/DropdownNavbarItem/styles.module.css
new file mode 100644
index 0000000..10ee92f
--- /dev/null
+++ b/src/theme/NavbarItem/DropdownNavbarItem/styles.module.css
@@ -0,0 +1,3 @@
+.dropdownNavbarItemMobile {
+ cursor: pointer;
+}
diff --git a/src/theme/NavbarItem/HtmlNavbarItem.tsx b/src/theme/NavbarItem/HtmlNavbarItem.tsx
new file mode 100644
index 0000000..0cf8719
--- /dev/null
+++ b/src/theme/NavbarItem/HtmlNavbarItem.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import clsx from 'clsx';
+
+import type {Props} from '@theme/NavbarItem/HtmlNavbarItem';
+
+export default function HtmlNavbarItem({
+ value,
+ className,
+ mobile = false,
+ isDropdownItem = false,
+}: Props): JSX.Element {
+ const Comp = isDropdownItem ? 'li' : 'div';
+ return (
+
+ );
+}
diff --git a/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx b/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx
new file mode 100644
index 0000000..c5f8773
--- /dev/null
+++ b/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import {useAlternatePageUtils} from '@docusaurus/theme-common/internal';
+import {translate} from '@docusaurus/Translate';
+import {useLocation} from '@docusaurus/router';
+import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
+import IconLanguage from '@theme/Icon/Language';
+import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem';
+import type {Props} from '@theme/NavbarItem/LocaleDropdownNavbarItem';
+
+import styles from './styles.module.css';
+
+export default function LocaleDropdownNavbarItem({
+ mobile,
+ dropdownItemsBefore,
+ dropdownItemsAfter,
+ queryString = '',
+ ...props
+}: Props): JSX.Element {
+ const {
+ i18n: {currentLocale, locales, localeConfigs},
+ } = useDocusaurusContext();
+ const alternatePageUtils = useAlternatePageUtils();
+ const {search, hash} = useLocation();
+
+ const localeItems = locales.map((locale): LinkLikeNavbarItemProps => {
+ const baseTo = `pathname://${alternatePageUtils.createUrl({
+ locale,
+ fullyQualified: false,
+ })}`;
+ // preserve ?search#hash suffix on locale switches
+ const to = `${baseTo}${search}${hash}${queryString}`;
+ return {
+ label: localeConfigs[locale]!.label,
+ lang: localeConfigs[locale]!.htmlLang,
+ to,
+ target: '_self',
+ autoAddBaseUrl: false,
+ className:
+ // eslint-disable-next-line no-nested-ternary
+ locale === currentLocale
+ ? // Similar idea as DefaultNavbarItem: select the right Infima active
+ // class name. This cannot be substituted with isActive, because the
+ // target URLs contain `pathname://` and therefore are not NavLinks!
+ mobile
+ ? 'menu__link--active'
+ : 'dropdown__link--active'
+ : '',
+ };
+ });
+
+ const items = [...dropdownItemsBefore, ...localeItems, ...dropdownItemsAfter];
+
+ // Mobile is handled a bit differently
+ const dropdownLabel = mobile
+ ? translate({
+ message: 'Languages',
+ id: 'theme.navbar.mobileLanguageDropdown.label',
+ description: 'The label for the mobile language switcher dropdown',
+ })
+ : localeConfigs[currentLocale]!.label;
+
+ return (
+
+
+ {dropdownLabel}
+ >
+ }
+ items={items}
+ />
+ );
+}
diff --git a/src/theme/NavbarItem/LocaleDropdownNavbarItem/styles.module.css b/src/theme/NavbarItem/LocaleDropdownNavbarItem/styles.module.css
new file mode 100644
index 0000000..8804a08
--- /dev/null
+++ b/src/theme/NavbarItem/LocaleDropdownNavbarItem/styles.module.css
@@ -0,0 +1,4 @@
+.iconLanguage {
+ vertical-align: text-bottom;
+ margin-right: 5px;
+}
diff --git a/src/theme/NavbarItem/NavbarNavLink.tsx b/src/theme/NavbarItem/NavbarNavLink.tsx
new file mode 100644
index 0000000..a85c8a9
--- /dev/null
+++ b/src/theme/NavbarItem/NavbarNavLink.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import Link from '@docusaurus/Link';
+import useBaseUrl from '@docusaurus/useBaseUrl';
+import isInternalUrl from '@docusaurus/isInternalUrl';
+import {isRegexpStringMatch} from '@docusaurus/theme-common';
+import IconExternalLink from '@theme/Icon/ExternalLink';
+import type {Props} from '@theme/NavbarItem/NavbarNavLink';
+
+export default function NavbarNavLink({
+ activeBasePath,
+ activeBaseRegex,
+ to,
+ href,
+ label,
+ html,
+ isDropdownLink,
+ prependBaseUrlToHref,
+ ...props
+}: Props): JSX.Element {
+ // TODO all this seems hacky
+ // {to: 'version'} should probably be forbidden, in favor of {to: '/version'}
+ const toUrl = useBaseUrl(to);
+ const activeBaseUrl = useBaseUrl(activeBasePath);
+ const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
+ const isExternalLink = label && href && !isInternalUrl(href);
+
+ // Link content is set through html XOR label
+ const linkContentProps = html
+ ? {dangerouslySetInnerHTML: {__html: html}}
+ : {
+ children: (
+ <>
+ {label}
+ {isExternalLink && (
+
+ )}
+ >
+ ),
+ };
+
+ if (href) {
+ return (
+
+ );
+ }
+
+ return (
+
+ activeBaseRegex
+ ? isRegexpStringMatch(activeBaseRegex, location.pathname)
+ : location.pathname.startsWith(activeBaseUrl),
+ })}
+ {...props}
+ {...linkContentProps}
+ />
+ );
+}
diff --git a/src/theme/NavbarItem/SearchNavbarItem.tsx b/src/theme/NavbarItem/SearchNavbarItem.tsx
new file mode 100644
index 0000000..87c05f3
--- /dev/null
+++ b/src/theme/NavbarItem/SearchNavbarItem.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import SearchBar from '@theme/SearchBar';
+import NavbarSearch from '@theme/Navbar/Search';
+import type {Props} from '@theme/NavbarItem/SearchNavbarItem';
+
+export default function SearchNavbarItem({
+ mobile,
+ className,
+}: Props): JSX.Element | null {
+ if (mobile) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+}
diff --git a/src/theme/NavbarItem/index.tsx b/src/theme/NavbarItem/index.tsx
new file mode 100644
index 0000000..45bb2bb
--- /dev/null
+++ b/src/theme/NavbarItem/index.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import ComponentTypes from '@theme/NavbarItem/ComponentTypes';
+import type {NavbarItemType, Props} from '@theme/NavbarItem';
+
+function normalizeComponentType(type: NavbarItemType, props: object) {
+ // Backward compatibility: navbar item with no type set
+ // but containing dropdown items should use the type "dropdown"
+ if (!type || type === 'default') {
+ return 'items' in props ? 'dropdown' : 'default';
+ }
+ return type;
+}
+
+export default function NavbarItem({type, ...props}: Props): JSX.Element {
+ const componentType = normalizeComponentType(type, props);
+ const NavbarItemComponent = ComponentTypes[componentType];
+ if (!NavbarItemComponent) {
+ throw new Error(`No NavbarItem component found for type "${type}".`);
+ }
+ return ;
+}
diff --git a/static/img/icon.svg b/static/img/icon.svg
new file mode 100644
index 0000000..8d0d8a4
--- /dev/null
+++ b/static/img/icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/static/img/logoDarkMode.svg b/static/img/logoDarkMode.svg
new file mode 100644
index 0000000..2f84f61
--- /dev/null
+++ b/static/img/logoDarkMode.svg
@@ -0,0 +1,5 @@
+
diff --git a/static/img/logoLightMode.svg b/static/img/logoLightMode.svg
new file mode 100644
index 0000000..ae42bd2
--- /dev/null
+++ b/static/img/logoLightMode.svg
@@ -0,0 +1,5 @@
+
From a6ad986fc6def3076f5a25e8987c6d5e1a81e9c9 Mon Sep 17 00:00:00 2001
From: zeke <40004347+KAJdev@users.noreply.github.com>
Date: Mon, 12 Aug 2024 18:45:01 -0800
Subject: [PATCH 4/4] better dark mode search background contrast
---
src/css/custom.css | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/css/custom.css b/src/css/custom.css
index f0bbc7a..6bb3f03 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -31,6 +31,7 @@
--ifm-color-primary-lightest: #beb0f3; /* Lightest tint for dark mode */
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); /* Highlighted code line background in dark mode */
--ifm-navbar-background-color: #000;
+ --docsearch-searchbox-background: #1d1d1d;
}
body {