diff --git a/package.json b/package.json
index ab39267ca6..0869824cd4 100644
--- a/package.json
+++ b/package.json
@@ -48,8 +48,8 @@
"next-query-params": "^5.0.1",
"next-sitemap": "^4.2.3",
"next-with-less": "^3.0.1",
- "nextra": "^3",
- "nextra-theme-docs": "^3",
+ "nextra": "3.3.1",
+ "nextra-theme-docs": "3.3.1",
"numbro": "2.5.0",
"p-limit": "^4.0.0",
"parser-front-matter": "1.6.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3770393c41..fb8006eaa9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -98,10 +98,10 @@ importers:
specifier: ^3.0.1
version: 3.0.1(less-loader@12.2.0(less@4.2.1))(less@4.2.1)(next@14.2.29(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
nextra:
- specifier: ^3
+ specifier: 3.3.1
version: 3.3.1(patch_hash=ytqsrocfyxyupt7yg3khzgrhfe)(@types/react@18.3.23)(next@14.2.29(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)
nextra-theme-docs:
- specifier: ^3
+ specifier: 3.3.1
version: 3.3.1(next@14.2.29(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@3.3.1(patch_hash=ytqsrocfyxyupt7yg3khzgrhfe)(@types/react@18.3.23)(next@14.2.29(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
numbro:
specifier: 2.5.0
diff --git a/src/components/index-page/hero.tsx b/src/components/index-page/hero.tsx
index 4d8588556a..5e5b709c7d 100644
--- a/src/components/index-page/hero.tsx
+++ b/src/components/index-page/hero.tsx
@@ -7,7 +7,7 @@ import logoBlurred from "./hero/logo-blurred.png"
export function Hero() {
return (
-
+
@@ -44,7 +44,7 @@ function HeroStripes() {
void
+}): ReactElement {
+ const routes = Object.fromEntries(
+ (menu.children || []).map(route => [route.name, route]),
+ )
+ return (
+
+ )
+}
+
+export function Navbar({ items }: NavBarProps): ReactElement {
+ const themeConfig = useThemeConfig()
+
+ const activeRoute = useFSRoute()
+ const { menu, setMenu } = useMenu()
+ const [submenuOpen, setSubmenuOpen] = useState(false)
+
+ return (
+
+
+
+
+
+ )
+}
+
+function BackdropBlur() {
+ const mask = "linear-gradient(to bottom, #000 0% 50%, transparent 50% 100%)"
+ const thickness = "1px"
+ return (
+ <>
+
+
+ >
+ )
+}
+
+export function NavbarPlaceholder({
+ className,
+ ...rest
+}: React.HTMLAttributes) {
+ return (
+
+ )
+}
+
+function SubmenuBackdrop({ className }: { className: string }) {
+ return (
+
+ )
+}
diff --git a/src/components/utils.tsx b/src/components/utils.tsx
new file mode 100644
index 0000000000..9074a85647
--- /dev/null
+++ b/src/components/utils.tsx
@@ -0,0 +1,8 @@
+export function renderComponent(
+ ComponentOrNode: React.FC | React.ReactNode,
+ props?: T,
+) {
+ if (!ComponentOrNode) return null
+ if (typeof ComponentOrNode !== "function") return ComponentOrNode
+ return
+}
diff --git a/src/globals.css b/src/globals.css
index 4dbefd6e5c..962c829ce7 100644
--- a/src/globals.css
+++ b/src/globals.css
@@ -3,12 +3,6 @@
@import "tailwindcss/utilities";
@import "tailwindcss/components";
-/* #region nextra tweaks (preferably removed later, replaced with components) */
-.nextra-nav-container > nav > div:nth-child(2) {
- margin-right: auto;
-}
-/* #endregion nextra tweaks */
-
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
@@ -517,10 +511,15 @@ div[id^="headlessui-menu-items"] {
@apply px-4 py-8 lg:px-12 xl:gap-x-24 xl:px-24 3xl:px-[240px];
}
+.gql-navbar-strip,
.gql-conf-navbar-strip {
@apply relative [contain:paint] before:sticky before:top-0 before:z-[9] before:-mt-[var(--navbar-h)] before:block before:h-[var(--navbar-h)] before:w-full before:content-[''];
}
+.gql-navbar-strip {
+ --navbar-h: var(--nextra-navbar-height);
+}
+
:root {
--navbar-h: 70px;
}
diff --git a/src/nextra-theme-docs.css b/src/nextra-theme-docs.css
index 3a07dfa7d2..fbe3ba187a 100644
--- a/src/nextra-theme-docs.css
+++ b/src/nextra-theme-docs.css
@@ -2087,56 +2087,6 @@ body,
background-color: rgb(var(--nextra-bg));
}
}
-.nextra-nav-container-blur {
- pointer-events: none;
- z-index: -1;
- --tw-shadow: 0 2px 4px #00000005, 0 1px 0 #0000000f;
- --tw-shadow-colored:
- 0 2px 4px var(--tw-shadow-color), 0 1px 0 var(--tw-shadow-color);
- box-shadow:
- var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
- var(--tw-shadow);
- width: 100%;
- height: 100%;
- position: absolute;
-}
-.nextra-nav-container-blur:is(html[class~="dark"] *) {
- --tw-shadow: 0 -1px 0 #ffffff1a inset;
- --tw-shadow-colored: inset 0 -1px 0 var(--tw-shadow-color);
- box-shadow:
- var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
- var(--tw-shadow);
-}
-@media (prefers-contrast: more) {
- .nextra-nav-container-blur {
- --tw-shadow: 0 0 0 1px #000;
- --tw-shadow-colored: 0 0 0 1px var(--tw-shadow-color);
- box-shadow:
- var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
- var(--tw-shadow);
- }
- .nextra-nav-container-blur:is(html[class~="dark"] *) {
- --tw-shadow: 0 0 0 1px #fff;
- --tw-shadow-colored: 0 0 0 1px var(--tw-shadow-color);
- box-shadow:
- var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
- var(--tw-shadow);
- }
-}
-.nextra-nav-container-blur {
- background-color: rgba(var(--nextra-bg), 0.7);
- --tw-backdrop-blur: blur(12px);
- -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness)
- var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale)
- var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert)
- var(--tw-backdrop-opacity) var(--tw-backdrop-saturate)
- var(--tw-backdrop-sepia);
- backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness)
- var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale)
- var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert)
- var(--tw-backdrop-opacity) var(--tw-backdrop-saturate)
- var(--tw-backdrop-sepia);
-}
.nextra-toc-footer,
.nextra-sidebar-footer {
border-top-width: 1px;
diff --git a/src/pages/_meta.tsx b/src/pages/_meta.tsx
index 104bf3ae14..fa6c9544c6 100644
--- a/src/pages/_meta.tsx
+++ b/src/pages/_meta.tsx
@@ -80,7 +80,12 @@ export default {
},
conf: {
type: "page",
- title: "GraphQLConf",
+ title: (
+
+ GraphQLConf
+ 2025
+
+ ),
route: "/conf/2025",
},
"graphql-js": {
diff --git a/theme.config.tsx b/theme.config.tsx
index 2580fae932..63fd1090aa 100644
--- a/theme.config.tsx
+++ b/theme.config.tsx
@@ -1,5 +1,9 @@
import { DocsThemeConfig, ThemeSwitch, useConfig } from "nextra-theme-docs"
import NextLink from "next/link"
+
+import { Navbar } from "@/components/navbar/navbar"
+import { useRouter } from "next/router"
+
import {
GraphQLWordmarkLogo,
StackOverflowIcon,
@@ -7,12 +11,12 @@ import {
DiscordIcon,
TwitterIcon,
} from "./src/icons"
-import { useRouter } from "next/router"
+
// import { createElement } from "react"
// import NextImage from "next-image-export-optimizer"
const graphQLLogo = (
-
+
)
const classes = {
@@ -201,26 +205,31 @@ export default {
>
)
},
- banner: {
- content: (
- <>
- 📣 GraphQLConf 2025 • Sept 08-10 • Amsterdam • Early bird tickets
- available & sponsorship opportunities open •{" "}
-
- Learn more
-
- >
- ),
- key: "graphqlconf-2024",
- },
+ // Hidden for now, Design is discussing it.
+ // banner: {
+ // content: (
+ // <>
+ // 📣 GraphQLConf 2025 • Sept 08-10 • Amsterdam • Early bird tickets
+ // available & sponsorship opportunities open •{" "}
+ //
+ // Learn more
+ //
+ // >
+ // ),
+ // key: "graphqlconf-2024",
+ // },
logo: graphQLLogo,
docsRepositoryBase:
"https://github.com/graphql/graphql.github.io/tree/source",
color: {
hue: 319,
+ lightness: {
+ light: 44.1,
+ dark: 90,
+ },
},
sidebar: {
defaultMenuCollapseLevel: 1,
@@ -229,7 +238,10 @@ export default {
content: Footer,
},
navbar: {
- extraContent: ,
+ component: Navbar,
+ extraContent: (
+
+ ),
},
toc: {
backToTop: true,