+ );
+}
+export default React.memo(ColorModeToggle);
diff --git a/website/src/theme/ColorModeToggle/styles.module.css b/website/src/theme/ColorModeToggle/styles.module.css
new file mode 100644
index 00000000..8459fc79
--- /dev/null
+++ b/website/src/theme/ColorModeToggle/styles.module.css
@@ -0,0 +1,28 @@
+.toggle {
+ width: 2rem;
+ height: 2rem;
+}
+
+.toggleButton {
+ -webkit-tap-highlight-color: transparent;
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ transition: background var(--ifm-transition-fast);
+}
+
+.toggleButton:hover {
+ background: var(--ifm-color-emphasis-200);
+}
+
+[data-theme='light'] .darkToggleIcon,
+[data-theme='dark'] .lightToggleIcon {
+ display: none;
+}
+
+.toggleButtonDisabled {
+ cursor: not-allowed;
+}
diff --git a/website/src/theme/Icon/DarkMode/index.js b/website/src/theme/Icon/DarkMode/index.js
new file mode 100644
index 00000000..5a5bc0d7
--- /dev/null
+++ b/website/src/theme/Icon/DarkMode/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+export default function IconDarkMode(props) {
+ return (
+
+ );
+}
diff --git a/website/src/theme/Icon/LightMode/index.js b/website/src/theme/Icon/LightMode/index.js
new file mode 100644
index 00000000..38c8e93c
--- /dev/null
+++ b/website/src/theme/Icon/LightMode/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+export default function IconLightMode(props) {
+ return (
+
+ );
+}
diff --git a/website/src/theme/Navbar/ColorModeToggle/index.js b/website/src/theme/Navbar/ColorModeToggle/index.js
new file mode 100644
index 00000000..a506863c
--- /dev/null
+++ b/website/src/theme/Navbar/ColorModeToggle/index.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import {useColorMode, useThemeConfig} from '@docusaurus/theme-common';
+import ColorModeToggle from '@theme/ColorModeToggle';
+import styles from './styles.module.css';
+export default function NavbarColorModeToggle({className}) {
+ const navbarStyle = useThemeConfig().navbar.style;
+ const disabled = useThemeConfig().colorMode.disableSwitch;
+ const {colorMode, setColorMode} = useColorMode();
+ if (disabled) {
+ return null;
+ }
+ return (
+
+ );
+}
diff --git a/website/src/theme/Navbar/ColorModeToggle/styles.module.css b/website/src/theme/Navbar/ColorModeToggle/styles.module.css
new file mode 100644
index 00000000..7bd077a6
--- /dev/null
+++ b/website/src/theme/Navbar/ColorModeToggle/styles.module.css
@@ -0,0 +1,3 @@
+.darkNavbarColorModeToggle:hover {
+ background: var(--ifm-color-gray-800);
+}
diff --git a/website/src/theme/Navbar/Content/index.js b/website/src/theme/Navbar/Content/index.js
new file mode 100644
index 00000000..a6500994
--- /dev/null
+++ b/website/src/theme/Navbar/Content/index.js
@@ -0,0 +1,81 @@
+import React from "react";
+import {
+ useThemeConfig,
+ ErrorCauseBoundary,
+ useColorMode,
+} 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 (
+
+
{left}
+
{right}
+
+ );
+}
+export default function NavbarContent() {
+ const mobileSidebar = useNavbarMobileSidebar();
+ const items = useNavbarItems();
+ const [leftItems, rightItems] = splitNavbarItems(items);
+ const searchBarItem = items.find((item) => item.type === "search");
+ return (
+
+ {!mobileSidebar.disabled && }
+
+
+ >
+ }
+ right={
+ // TODO stop hardcoding items?
+ // Ask the user to add the respective navbar items => more flexible
+ <>
+
+
+ {!searchBarItem && (
+
+
+
+ )}
+ >
+ }
+ />
+ );
+}
diff --git a/website/src/theme/Navbar/Content/styles.module.css b/website/src/theme/Navbar/Content/styles.module.css
new file mode 100644
index 00000000..4c9471e1
--- /dev/null
+++ b/website/src/theme/Navbar/Content/styles.module.css
@@ -0,0 +1,8 @@
+/*
+Hide color mode toggle in small viewports
+ */
+@media (max-width: 996px) {
+ .colorModeToggle {
+ display: none;
+ }
+}
diff --git a/website/src/theme/Navbar/Layout/index.js b/website/src/theme/Navbar/Layout/index.js
new file mode 100644
index 00000000..492a9290
--- /dev/null
+++ b/website/src/theme/Navbar/Layout/index.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import clsx from 'clsx';
+import {useThemeConfig} from '@docusaurus/theme-common';
+import {
+ useHideableNavbar,
+ useNavbarMobileSidebar,
+} from '@docusaurus/theme-common/internal';
+import {translate} from '@docusaurus/Translate';
+import NavbarMobileSidebar from '@theme/Navbar/MobileSidebar';
+import styles from './styles.module.css';
+function NavbarBackdrop(props) {
+ return (
+
+ );
+}
+export default function NavbarLayout({children}) {
+ const {
+ navbar: {hideOnScroll, style},
+ } = useThemeConfig();
+ const mobileSidebar = useNavbarMobileSidebar();
+ const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
+ return (
+
+ );
+}
diff --git a/website/src/theme/Navbar/Layout/styles.module.css b/website/src/theme/Navbar/Layout/styles.module.css
new file mode 100644
index 00000000..e72891a4
--- /dev/null
+++ b/website/src/theme/Navbar/Layout/styles.module.css
@@ -0,0 +1,7 @@
+.navbarHideable {
+ transition: transform var(--ifm-transition-fast) ease;
+}
+
+.navbarHidden {
+ transform: translate3d(0, calc(-100% - 2px), 0);
+}
diff --git a/website/src/theme/Navbar/Logo/index.js b/website/src/theme/Navbar/Logo/index.js
new file mode 100644
index 00000000..f0fa51ff
--- /dev/null
+++ b/website/src/theme/Navbar/Logo/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import Logo from '@theme/Logo';
+export default function NavbarLogo() {
+ return (
+
+ );
+}
diff --git a/website/src/theme/Navbar/MobileSidebar/Header/index.js b/website/src/theme/Navbar/MobileSidebar/Header/index.js
new file mode 100644
index 00000000..67e9e443
--- /dev/null
+++ b/website/src/theme/Navbar/MobileSidebar/Header/index.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal';
+import {translate} from '@docusaurus/Translate';
+import NavbarColorModeToggle from '@theme/Navbar/ColorModeToggle';
+import IconClose from '@theme/Icon/Close';
+import NavbarLogo from '@theme/Navbar/Logo';
+function CloseButton() {
+ const mobileSidebar = useNavbarMobileSidebar();
+ return (
+
+ );
+}
+export default function NavbarMobileSidebarHeader() {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/website/src/theme/Navbar/MobileSidebar/Layout/index.js b/website/src/theme/Navbar/MobileSidebar/Layout/index.js
new file mode 100644
index 00000000..b19eb2f9
--- /dev/null
+++ b/website/src/theme/Navbar/MobileSidebar/Layout/index.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import clsx from 'clsx';
+import {useNavbarSecondaryMenu} from '@docusaurus/theme-common/internal';
+export default function NavbarMobileSidebarLayout({
+ header,
+ primaryMenu,
+ secondaryMenu,
+}) {
+ const {shown: secondaryMenuShown} = useNavbarSecondaryMenu();
+ return (
+
+ {header}
+
+
{primaryMenu}
+
{secondaryMenu}
+
+
+ );
+}
diff --git a/website/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.js b/website/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.js
new file mode 100644
index 00000000..9c5d0ec0
--- /dev/null
+++ b/website/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import {useThemeConfig} from '@docusaurus/theme-common';
+import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal';
+import NavbarItem from '@theme/NavbarItem';
+function useNavbarItems() {
+ // TODO temporary casting until ThemeConfig type is improved
+ return useThemeConfig().navbar.items;
+}
+// The primary menu displays the navbar items
+export default function NavbarMobilePrimaryMenu() {
+ const mobileSidebar = useNavbarMobileSidebar();
+ // TODO how can the order be defined for mobile?
+ // Should we allow providing a different list of items?
+ const items = useNavbarItems();
+ return (
+