diff --git a/components/docsearch.tsx b/components/docsearch.tsx
index 668281c..b02490c 100644
--- a/components/docsearch.tsx
+++ b/components/docsearch.tsx
@@ -2,6 +2,7 @@
// sample code from https://docsearch.algolia.com/docs/docsearch
import { DocSearch } from '@docsearch/react';
+import { useThemeConfig } from 'nextra-theme-docs'
import '@docsearch/css';
@@ -11,6 +12,7 @@ function AlgoliaSearch() {
appId={process.env.NEXT_SEARCH_ALGOLIA_APP_ID || 'NKGLZZZUBC'}
indexName={process.env.NEXT_SEARCH_ALGOLIA_INDEX_NAME || 'notenextra_trance_0'}
apiKey={process.env.NEXT_SEARCH_ALGOLIA_API_KEY || '727b389a61e862e590dfab9ce9df31a2'}
+ theme={useThemeConfig().darkMode ? 'dark' : 'light'}
/>
);
}
diff --git a/components/navbar.client.tsx b/components/navbar.client.tsx
new file mode 100644
index 0000000..926f0b7
--- /dev/null
+++ b/components/navbar.client.tsx
@@ -0,0 +1,188 @@
+'use client'
+
+import {
+ MenuItem as _MenuItem,
+ Menu,
+ MenuButton,
+ MenuItems
+} from '@headlessui/react'
+import cn from 'clsx'
+import { Anchor, Button } from 'nextra/components'
+import { useFSRoute } from 'nextra/hooks'
+import { ArrowRightIcon, MenuIcon } from 'nextra/icons'
+import type { MenuItem } from 'nextra/normalize-pages'
+import type { FC, ReactNode } from 'react'
+import { setMenu, useConfig, useMenu, useThemeConfig } from 'nextra-theme-docs'
+import { usePathname } from 'next/navigation'
+import { normalizePages } from 'nextra/normalize-pages'
+import { PageMapItem } from 'nextra'
+
+const classes = {
+ link: cn(
+ 'x:text-sm x:contrast-more:text-gray-700 x:contrast-more:dark:text-gray-100 x:whitespace-nowrap',
+ 'x:text-gray-600 x:hover:text-black x:dark:text-gray-400 x:dark:hover:text-gray-200',
+ 'x:ring-inset x:transition-colors'
+ )
+}
+
+const NavbarMenu: FC<{
+ menu: MenuItem
+ children: ReactNode
+}> = ({ menu, children }) => {
+ const routes = Object.fromEntries(
+ (menu.children || []).map(route => [route.name, route])
+ )
+ return (
+
+ )
+}
+
+const isMenu = (page: any): page is MenuItem => page.type === 'menu'
+
+export const ClientNavbar: FC<{
+ pageMap: PageMapItem[]
+ children: ReactNode
+ className?: string
+}> = ({ pageMap, children, className }) => {
+
+ const { topLevelNavbarItems } = normalizePages({
+ list: pageMap,
+ route: usePathname()
+ })
+
+ // filter out titles for elements in topLevelNavbarItems with non empty route
+ const existingCourseNames = new Set(
+ topLevelNavbarItems.filter(
+ item => !('href' in item)
+ ).map(item => item.title)
+ )
+ // filter out elements in topLevelNavbarItems with url but have title in existingCourseNames
+ const filteredTopLevelNavbarItems = topLevelNavbarItems.filter(item => !('href' in item && existingCourseNames.has(item.title)))
+
+ // or even better, remove all old doc page generated links
+ // this don't make sense because it will destroy the navbar structure highlight for children pages
+ // const filteredTopLevelNavbarItems = topLevelNavbarItems.filter(item => !('firstChildRoute' in item))
+
+ // const items = topLevelNavbarItems
+ // use filteredTopLevelNavbarItems to generate items
+ const items = filteredTopLevelNavbarItems
+
+ const themeConfig = useThemeConfig()
+
+ const pathname = useFSRoute()
+ const menu = useMenu()
+
+ return (
+ <>
+
+ {items.map((page, _index, arr) => {
+ if ('display' in page && page.display === 'hidden') return
+ if (isMenu(page)) {
+ return (
+
+ {page.title}
+
+ )
+ }
+ const href =
+ // If it's a directory
+ ('frontMatter' in page ? page.route : page.firstChildRoute) ||
+ page.href ||
+ page.route
+
+ const isCurrentPage =
+ href === pathname ||
+ (pathname.startsWith(page.route + '/') &&
+ arr.every(item => !('href' in item) || item.href !== pathname)) ||
+ undefined
+
+ return (
+
+ {page.title}
+
+ )
+ })}
+
+ {themeConfig.search && (
+ {themeConfig.search}
+ )}
+
+ {children}
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/components/navbar.tsx b/components/navbar.tsx
new file mode 100644
index 0000000..d63424b
--- /dev/null
+++ b/components/navbar.tsx
@@ -0,0 +1,170 @@
+// customized navbar component, modified from https://github.com/shuding/nextra/blob/c8238813e1ba425cdd72783d57707b0ff3ca52ea/examples/custom-theme/app/_components/navbar.tsx#L9
+
+// Rebuild from source code https://github.com/shuding/nextra/tree/c8238813e1ba425cdd72783d57707b0ff3ca52ea/packages/nextra-theme-docs/src/components/navbar
+
+'use client'
+
+import { usePathname } from 'next/navigation'
+import type { PageMapItem } from 'nextra'
+import { Anchor } from 'nextra/components'
+import { normalizePages } from 'nextra/normalize-pages'
+import type { FC, ReactNode } from 'react'
+
+import cn from 'clsx'
+// eslint-disable-next-line no-restricted-imports -- since we don't need `newWindow` prop
+import NextLink from 'next/link'
+import { DiscordIcon, GitHubIcon } from 'nextra/icons'
+import { ClientNavbar } from './navbar.client'
+
+// export const Navbar: FC<{ pageMap: PageMapItem[] }> = ({ pageMap }) => {
+// const pathname = usePathname()
+// const { topLevelNavbarItems } = normalizePages({
+// list: pageMap,
+// route: pathname
+// })
+// return (
+//
+// {filteredTopLevelNavbarItems.map(item => {
+
+// const route = item.route || ('href' in item ? item.href! : '')
+// return (
+// -
+//
+// {item.title}
+//
+//
+// )
+// })}
+//
+// )
+// }
+
+
+/* TODO: eslint typescript-sort-keys/interface: error */
+
+interface NavbarProps {
+ /**
+ * Page map.
+ */
+ pageMap: PageMapItem[]
+ /**
+ * Extra content after the last icon.
+ */
+ children?: ReactNode
+ /**
+ * Specifies whether the logo should have a link or provides the URL for the logo's link.
+ * @default true
+ */
+ logoLink?: string | boolean
+ /**
+ * Logo of the website.
+ */
+ logo: ReactNode
+ /**
+ * URL of the project homepage.
+ */
+ projectLink?: string
+ /**
+ * Icon of the project link.
+ * @default
+ */
+ projectIcon?: ReactNode
+ /**
+ * URL of the chat link.
+ */
+ chatLink?: string
+ /**
+ * Icon of the chat link.
+ * @default
+ */
+ chatIcon?: ReactNode
+ /**
+ * CSS class name.
+ */
+ className?: string
+ /**
+ * Aligns navigation links to the specified side.
+ * @default 'right'
+ */
+ align?: 'left' | 'right'
+}
+
+// Fix compiler error
+// Expression type `JSXElement` cannot be safely reordered
+const defaultGitHubIcon = (
+
+)
+const defaultChatIcon =
+
+export const Navbar: FC = ({
+ pageMap,
+ children,
+ logoLink = true,
+ logo,
+ projectLink,
+ projectIcon = defaultGitHubIcon,
+ chatLink,
+ chatIcon = defaultChatIcon,
+ className,
+ align = 'right'
+}) => {
+ const logoClass = cn(
+ 'x:flex x:items-center',
+ align === 'left' ? 'x:max-md:me-auto' : 'x:me-auto'
+ )
+ return (
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/content/_meta.js b/content/_meta.js
index adbdd38..b5638da 100644
--- a/content/_meta.js
+++ b/content/_meta.js
@@ -26,180 +26,173 @@ export default {
},
/* Load link with relative path */
Math3200_link: {
- title: 'Math 3200',
+ title: 'Math3200',
+ type: 'page',
href: '/Math3200'
},
Math429_link: {
- title: 'Math 429',
+ title: 'Math429',
+ type: 'page',
href: '/Math429'
},
Math4111_link: {
- title: 'Math 4111',
+ title: 'Math4111',
+ type: 'page',
href: '/Math4111'
},
Math4121_link: {
- title: 'Math 4121',
+ title: 'Math4121',
+ type: 'page',
href: '/Math4121'
},
Math4201_link: {
- title: 'Math 4201',
+ title: 'Math4201',
+ type: 'page',
href: '/Math4201'
},
Math416_link: {
- title: 'Math 416',
+ title: 'Math416',
+ type: 'page',
href: '/Math416'
},
Math401_link: {
- title: 'Math 401',
+ title: 'Math401',
+ type: 'page',
href: '/Math401'
},
CSE332S_link: {
- title: 'CSE 332S',
+ title: 'CSE332S',
+ type: 'page',
href: '/CSE332S'
},
CSE347_link: {
- title: 'CSE 347',
+ title: 'CSE347',
+ type: 'page',
href: '/CSE347'
},
CSE442T_link: {
- title: 'CSE 442T',
+ title: 'CSE442T',
+ type: 'page',
href: '/CSE442T'
},
CSE5313_link: {
- title: 'CSE 5313',
+ title: 'CSE5313',
+ type: 'page',
href: '/CSE5313'
},
CSE510_link: {
- title: 'CSE 510',
+ title: 'CSE510',
+ type: 'page',
href: '/CSE510'
},
CSE559A_link: {
- title: 'CSE 559A',
+ title: 'CSE559A',
+ type: 'page',
href: '/CSE559A'
},
CSE5519_link: {
- title: 'CSE 5519',
+ title: 'CSE5519',
+ type: 'page',
href: '/CSE5519'
},
/* Math Courses Start */
Math3200: {
- display: 'hidden',
+ title: 'Math3200',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
Math429:{
- display: 'hidden',
+ title: 'Math429',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
Math4111: {
- display: 'hidden',
+ title: 'Math4111',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
Math4121: {
- display: 'hidden',
+ title: 'Math4121',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
Math4201: {
- display: 'hidden',
+ title: 'Math4201',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
Math416: {
- display: 'hidden',
+ title: 'Math416',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
Math401: {
- display: 'hidden',
+ title: 'Math401',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
/* Math Courses End */
/* CSE Courses Start */
CSE332S: {
- display: 'hidden',
title: 'CSE332S',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
CSE347: {
- display: 'hidden',
title: 'CSE347',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
CSE442T: {
- display: 'hidden',
title: 'CSE442T',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
CSE5313: {
- display: 'hidden',
title: 'CSE5313',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
CSE510: {
- display: 'hidden',
title: 'CSE510',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
CSE559A: {
- display: 'hidden',
title: 'CSE559A',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
CSE5519: {
- display: 'hidden',
title: 'CSE5519',
type: 'page',
theme:{
- sidebar: false,
timestamp: true,
}
},
diff --git a/content/layout.tsx b/content/layout.tsx
index dad73d2..504aad1 100644
--- a/content/layout.tsx
+++ b/content/layout.tsx
@@ -1,10 +1,11 @@
/* eslint-env node */
-import { Footer, Layout, Navbar } from 'nextra-theme-docs'
+import { Footer, Layout} from 'nextra-theme-docs'
import { Banner, Head } from 'nextra/components'
import { getPageMap } from 'nextra/page-map'
import 'nextra-theme-docs/style.css'
import { SpeedInsights } from "@vercel/speed-insights/next"
import { Analytics } from "@vercel/analytics/react"
+import { Navbar } from '../components/navbar'
export const metadata = {
metadataBase: new URL('https://notenextra.trance-0.com'),
@@ -27,8 +28,10 @@ export const metadata = {
}
export default async function RootLayout({ children }) {
+ const pageMap = await getPageMap()
const navbar = (