Skip to content

Commit a49550b

Browse files
committed
style the navbar more
1 parent 10e679b commit a49550b

File tree

5 files changed

+101
-91
lines changed

5 files changed

+101
-91
lines changed

src/components/navbar/navbar.tsx

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { MenuItem, Menu, MenuButton, MenuItems } from "@headlessui/react"
2-
import cn from "clsx"
2+
import clsx from "clsx"
33
// eslint-disable-next-line no-restricted-imports -- since we don't need newWindow prop
44
import NextLink from "next/link"
55
import { Button } from "nextra/components"
@@ -19,13 +19,7 @@ export interface NavBarProps {
1919
}
2020

2121
const classes = {
22-
link: cn(
23-
"_text-sm contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100",
24-
),
25-
active: cn("_font-medium _subpixel-antialiased"),
26-
inactive: cn(
27-
"_text-gray-600 hover:_text-gray-800 dark:_text-gray-400 dark:hover:_text-gray-200",
28-
),
22+
link: "typography-menu flex items-center text-neu-900 px-3 py-1 nextra-focus [text-box:trim-both_cap_alphabetic] leading-none",
2923
}
3024

3125
function NavbarMenu({
@@ -42,33 +36,32 @@ function NavbarMenu({
4236
<Menu>
4337
<MenuButton
4438
className={({ focus }) =>
45-
cn(
39+
clsx(
4640
classes.link,
47-
classes.inactive,
48-
"max-md:_hidden _items-center _whitespace-nowrap _flex _gap-1.5 _ring-inset",
41+
"flex items-center gap-1.5 whitespace-nowrap max-md:hidden",
4942
focus && "nextra-focusable",
5043
)
5144
}
5245
>
5346
{children}
54-
{"->"}
5547
</MenuButton>
5648
<MenuItems
5749
transition
50+
portal={false}
51+
modal={false}
5852
className={({ open }) =>
59-
cn(
60-
"motion-reduce:_transition-none",
61-
"nextra-focus",
62-
open ? "_opacity-100" : "_opacity-0",
63-
"nextra-scrollbar _transition-opacity",
64-
"_border _border-black/5 dark:_border-white/20",
65-
"_backdrop-blur-lg bg-[rgb(var(--nextra-bg),.8)]", // todo: full screen overlay
66-
"_z-20 _rounded-md _py-1 _text-sm",
53+
clsx(
54+
"motion-reduce:transition-none",
55+
"focus-visible:outline-none",
56+
open ? "opacity-100" : "opacity-0",
57+
"nextra-scrollbar transition-opacity",
58+
"bg-[rgb(var(--nextra-bg),.8)] backdrop-blur-lg", // todo: full screen overlay
59+
"z-20 rounded-md py-1 text-sm",
6760
// headlessui adds max-height as style, use !important to override
68-
"!_max-h-[min(calc(100vh-5rem),256px)]",
61+
"!max-h-[min(calc(100vh-5rem),256px)]",
6962
)
7063
}
71-
anchor={{ to: "top end", gap: 10, padding: 16 }}
64+
anchor={{ to: "top start", gap: 21, padding: 16 }}
7265
>
7366
{Object.entries(menu.items || {}).map(([key, item]) => (
7467
<MenuItem
@@ -97,26 +90,32 @@ export function Navbar({ items }: NavBarProps): ReactElement {
9790
const { menu, setMenu } = useMenu()
9891

9992
return (
100-
<div className="nextra-nav-container _top-0 _z-20 _w-full _bg-transparent print:_hidden fixed">
101-
<div className="nextra-nav-container-blur" />
102-
<nav className="mx-auto flex h-[var(--nextra-navbar-height)] max-w-[90rem] items-center justify-end gap-4 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)]">
93+
<div
94+
className={clsx(
95+
"nextra-nav-container _top-0 _z-20 _w-full _bg-transparent print:_hidden",
96+
activeRoute === "/" ? "fixed" : "sticky",
97+
)}
98+
>
99+
<BackdropBlur />
100+
<nav className="mx-auto flex h-[var(--nextra-navbar-height)] max-w-[90rem] items-center justify-end pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)]">
103101
{themeConfig.logoLink ? (
104102
<NextLink
105103
href={
106104
typeof themeConfig.logoLink === "string"
107105
? themeConfig.logoLink
108106
: "/"
109107
}
110-
className="nextra-focus flex items-center hover:opacity-75 ltr:mr-auto rtl:ml-auto"
108+
className="nextra-focus flex items-center hover:opacity-75"
111109
>
112110
{renderComponent(themeConfig.logo)}
113111
</NextLink>
114112
) : (
115-
<div className="flex items-center ltr:mr-auto rtl:ml-auto">
113+
<div className="flex items-center">
116114
{renderComponent(themeConfig.logo)}
117115
</div>
118116
)}
119-
<div className="nextra-scrollbar flex gap-4 overflow-x-auto py-1.5">
117+
<div className="flex-1" />
118+
<div className="-mx-2 flex overflow-x-auto px-2 py-1.5 lg:gap-2 xl:absolute xl:left-1/2 xl:-translate-x-1/2">
120119
{items.map(pageOrMenu => {
121120
if (pageOrMenu.display === "hidden") return null
122121

@@ -145,12 +144,10 @@ export function Navbar({ items }: NavBarProps): ReactElement {
145144
<Anchor
146145
href={href}
147146
key={href}
148-
className={cn(
147+
className={clsx(
149148
classes.link,
150-
"max-md:_hidden _whitespace-nowrap _ring-inset",
151-
!isActive || page.newWindow
152-
? classes.inactive
153-
: classes.active,
149+
"whitespace-nowrap max-md:hidden",
150+
isActive && !page.newWindow && "font-medium",
154151
)}
155152
target={page.newWindow ? "_blank" : undefined}
156153
aria-current={!page.newWindow && isActive}
@@ -183,16 +180,63 @@ export function Navbar({ items }: NavBarProps): ReactElement {
183180
<Button
184181
aria-label="Menu"
185182
className={({ active }) =>
186-
cn(
187-
"nextra-hamburger _rounded md:_hidden",
188-
active && "_bg-gray-400/20",
183+
clsx(
184+
"nextra-hamburger p-2 text-pri-base md:hidden",
185+
active && "bg-neu-400/20",
189186
)
190187
}
191188
onClick={() => setMenu(!menu)}
192189
>
193-
{menu ? <CloseIcon /> : <MenuIcon />}
190+
{menu ? (
191+
<CloseIcon className="size-5" />
192+
) : (
193+
<MenuIcon className="size-5" />
194+
)}
194195
</Button>
195196
</nav>
196197
</div>
197198
)
198199
}
200+
201+
function BackdropBlur() {
202+
const mask = "linear-gradient(to bottom, #000 0% 50%, transparent 50% 100%)"
203+
const thickness = "1px"
204+
return (
205+
<>
206+
<div
207+
// note: we can't use the background trick to reduce flickering, because we have many section
208+
// background colors and big images, so we'd have to change the --bg var with javascript
209+
className="pointer-events-none absolute inset-0 -z-10 h-[200%] backdrop-blur-[12.8px]"
210+
style={{
211+
maskImage: mask,
212+
WebkitMaskImage: mask,
213+
background:
214+
"linear-gradient(to bottom,rgb(var(--nextra-bg),.97) 0%, rgb(var(--nextra-bg),.5) 50% 100%)",
215+
}}
216+
/>
217+
<div
218+
className="pointer-events-none absolute inset-0 h-full translate-y-full bg-white/10"
219+
style={{
220+
backdropFilter: "blur(8px) brightness(120%) saturate(113%)",
221+
maskImage: `linear-gradient(to bottom, black 0, black ${thickness}, transparent ${thickness})`,
222+
}}
223+
/>
224+
</>
225+
)
226+
}
227+
228+
export function NavbarPlaceholder({
229+
className,
230+
...rest
231+
}: React.HTMLAttributes<HTMLDivElement>) {
232+
return (
233+
<div
234+
// placeholder: the colors here on `before` must match the ones on Hero `before` strip
235+
className={clsx(
236+
"absolute h-[calc(var(--nextra-navbar-height)+1px)] w-full before:absolute before:top-0 before:h-[calc(var(--nextra-navbar-height)+1px)] before:w-full",
237+
className,
238+
)}
239+
{...rest}
240+
/>
241+
)
242+
}

src/globals.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,10 +511,15 @@ div[id^="headlessui-menu-items"] {
511511
@apply px-4 py-8 lg:px-12 xl:gap-x-24 xl:px-24 3xl:px-[240px];
512512
}
513513

514+
.gql-navbar-strip,
514515
.gql-conf-navbar-strip {
515516
@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-[''];
516517
}
517518

519+
.gql-navbar-strip {
520+
--navbar-h: var(--nextra-navbar-height);
521+
}
522+
518523
:root {
519524
--navbar-h: 70px;
520525
}

src/nextra-theme-docs.css

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,56 +2087,6 @@ body,
20872087
background-color: rgb(var(--nextra-bg));
20882088
}
20892089
}
2090-
.nextra-nav-container-blur {
2091-
pointer-events: none;
2092-
z-index: -1;
2093-
--tw-shadow: 0 2px 4px #00000005, 0 1px 0 #0000000f;
2094-
--tw-shadow-colored:
2095-
0 2px 4px var(--tw-shadow-color), 0 1px 0 var(--tw-shadow-color);
2096-
box-shadow:
2097-
var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
2098-
var(--tw-shadow);
2099-
width: 100%;
2100-
height: 100%;
2101-
position: absolute;
2102-
}
2103-
.nextra-nav-container-blur:is(html[class~="dark"] *) {
2104-
--tw-shadow: 0 -1px 0 #ffffff1a inset;
2105-
--tw-shadow-colored: inset 0 -1px 0 var(--tw-shadow-color);
2106-
box-shadow:
2107-
var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
2108-
var(--tw-shadow);
2109-
}
2110-
@media (prefers-contrast: more) {
2111-
.nextra-nav-container-blur {
2112-
--tw-shadow: 0 0 0 1px #000;
2113-
--tw-shadow-colored: 0 0 0 1px var(--tw-shadow-color);
2114-
box-shadow:
2115-
var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
2116-
var(--tw-shadow);
2117-
}
2118-
.nextra-nav-container-blur:is(html[class~="dark"] *) {
2119-
--tw-shadow: 0 0 0 1px #fff;
2120-
--tw-shadow-colored: 0 0 0 1px var(--tw-shadow-color);
2121-
box-shadow:
2122-
var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
2123-
var(--tw-shadow);
2124-
}
2125-
}
2126-
.nextra-nav-container-blur {
2127-
background-color: rgba(var(--nextra-bg), 0.7);
2128-
--tw-backdrop-blur: blur(12px);
2129-
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness)
2130-
var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale)
2131-
var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert)
2132-
var(--tw-backdrop-opacity) var(--tw-backdrop-saturate)
2133-
var(--tw-backdrop-sepia);
2134-
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness)
2135-
var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale)
2136-
var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert)
2137-
var(--tw-backdrop-opacity) var(--tw-backdrop-saturate)
2138-
var(--tw-backdrop-sepia);
2139-
}
21402090
.nextra-toc-footer,
21412091
.nextra-sidebar-footer {
21422092
border-top-width: 1px;

src/pages/_meta.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ export default {
8080
},
8181
conf: {
8282
type: "page",
83-
title: "GraphQLConf",
83+
title: (
84+
<span className="[a:has(>&)]:[a:has(>&)]:border [a:has(>&)]:border [a:has(>&)]:border-current [a:has(>&)]:text-pri-base dark:[a:has(>&)]:text-pri-light">
85+
GraphQLConf
86+
<span className="max-xl:hidden"> 2025</span>
87+
</span>
88+
),
8489
route: "/conf/2025",
8590
},
8691
"graphql-js": {

theme.config.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { DocsThemeConfig, ThemeSwitch, useConfig } from "nextra-theme-docs"
22
import NextLink from "next/link"
3-
import { useRouter } from "next/router"
43

54
import { Navbar } from "@/components/navbar/navbar"
5+
import { useRouter } from "next/router"
66

77
import {
88
GraphQLWordmarkLogo,
@@ -16,7 +16,7 @@ import {
1616
// import NextImage from "next-image-export-optimizer"
1717

1818
const graphQLLogo = (
19-
<GraphQLWordmarkLogo className="nextra-logo h-8" title="GraphQL" />
19+
<GraphQLWordmarkLogo className="nextra-logo h-6" title="GraphQL" />
2020
)
2121

2222
const classes = {
@@ -225,6 +225,10 @@ export default {
225225
"https://github.com/graphql/graphql.github.io/tree/source",
226226
color: {
227227
hue: 319,
228+
lightness: {
229+
light: 44.1,
230+
dark: 90,
231+
},
228232
},
229233
sidebar: {
230234
defaultMenuCollapseLevel: 1,
@@ -234,7 +238,9 @@ export default {
234238
},
235239
navbar: {
236240
component: Navbar,
237-
extraContent: <ThemeSwitch lite className="[&_span]:hidden" />,
241+
extraContent: (
242+
<ThemeSwitch lite className="max-lg:hidden [&_span]:hidden" />
243+
),
238244
},
239245
toc: {
240246
backToTop: true,

0 commit comments

Comments
 (0)