Skip to content

Commit 29e49c5

Browse files
authored
Merge pull request #15642 from ethereum/nav-ssr-loading
refactor: nav to server component; add loading states
2 parents eb5ed7d + 7ab5398 commit 29e49c5

File tree

14 files changed

+280
-216
lines changed

14 files changed

+280
-216
lines changed

src/components/LanguagePicker/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use client"
2+
13
import { useParams } from "next/navigation"
24

35
import { cn } from "@/lib/utils/cn"

src/components/Nav/Client/index.tsx

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
"use client"
2+
3+
import { useRef } from "react"
4+
import dynamic from "next/dynamic"
5+
import { useLocale } from "next-intl"
6+
import { BsTranslate } from "react-icons/bs"
7+
8+
import SearchButton from "@/components/Search/SearchButton"
9+
import SearchInputButton from "@/components/Search/SearchInputButton"
10+
import { Button } from "@/components/ui/buttons/Button"
11+
import { Skeleton } from "@/components/ui/skeleton"
12+
13+
import { DESKTOP_LANGUAGE_BUTTON_NAME } from "@/lib/constants"
14+
15+
import { useNavigation } from "../useNavigation"
16+
import { useThemeToggle } from "../useThemeToggle"
17+
18+
import { useBreakpointValue } from "@/hooks/useBreakpointValue"
19+
import { useTranslation } from "@/hooks/useTranslation"
20+
21+
const Menu = dynamic(() => import("../Menu"), {
22+
ssr: false,
23+
loading: () => (
24+
<div className="me-8 flex w-full items-center gap-10 px-6 max-md:hidden">
25+
{Array.from({ length: 5 }).map((_, i) => (
26+
<Skeleton key={i} className="h-6 w-12 py-2" />
27+
))}
28+
</div>
29+
),
30+
})
31+
32+
const MobileMenuLoading = () => (
33+
<Skeleton data-label="mobile-menu" className="ms-2 size-6" />
34+
)
35+
36+
const MobileNavMenu = dynamic(() => import("../Mobile"), {
37+
ssr: false,
38+
loading: MobileMenuLoading,
39+
})
40+
41+
const SearchProvider = dynamic(() => import("../../Search"), {
42+
ssr: false,
43+
loading: () => (
44+
<>
45+
<div className="flex items-center gap-6 px-2 max-md:hidden xl:px-3">
46+
<Skeleton
47+
data-label="search-xl"
48+
className="hidden h-6 w-[169px] xl:flex"
49+
/>
50+
<Skeleton data-label="search" className="size-6 xl:hidden" />
51+
</div>
52+
<div className="flex items-center md:hidden">
53+
<Skeleton data-label="search" className="mx-2 size-6" />
54+
<MobileMenuLoading />
55+
</div>
56+
</>
57+
),
58+
})
59+
60+
const LanguagePicker = dynamic(() => import("../../LanguagePicker"), {
61+
ssr: false,
62+
loading: () => (
63+
// LG skeleton width approximates English "[icon] Languages EN" text width
64+
<Skeleton className="h-6 max-md:hidden md:mx-2 md:w-[54px] lg:mx-3 lg:w-[8.875rem]" />
65+
),
66+
})
67+
68+
const ClientSideNav = () => {
69+
const { t } = useTranslation("common")
70+
const locale = useLocale()
71+
72+
const { linkSections } = useNavigation()
73+
const { toggleColorMode, ThemeIcon, themeIconAriaLabel } = useThemeToggle()
74+
75+
const languagePickerRef = useRef<HTMLButtonElement>(null)
76+
77+
// avoid rendering/adding desktop Menu version to DOM on mobile
78+
const desktopScreen = useBreakpointValue({ base: false, md: true })
79+
80+
return (
81+
<>
82+
{desktopScreen && (
83+
<Menu
84+
className="animate-fade-in max-md:hidden"
85+
sections={linkSections}
86+
/>
87+
)}
88+
89+
<div className="flex items-center">
90+
<SearchProvider>
91+
{({ onOpen }) => {
92+
return (
93+
<>
94+
<SearchInputButton
95+
className="animate-fade-in max-xl:hidden"
96+
onClick={onOpen}
97+
/>
98+
<SearchButton
99+
className="animate-fade-in xl:hidden"
100+
onClick={onOpen}
101+
/>
102+
103+
{!desktopScreen && (
104+
<MobileNavMenu
105+
toggleColorMode={toggleColorMode}
106+
linkSections={linkSections}
107+
toggleSearch={onOpen}
108+
className="flex animate-fade-in md:hidden"
109+
/>
110+
)}
111+
</>
112+
)
113+
}}
114+
</SearchProvider>
115+
116+
{desktopScreen && (
117+
<Button
118+
aria-label={themeIconAriaLabel}
119+
variant="ghost"
120+
isSecondary
121+
className="group animate-fade-in px-2 max-md:hidden xl:px-3 [&>svg]:transition-transform [&>svg]:duration-500 [&>svg]:hover:rotate-12 [&>svg]:hover:text-primary-hover"
122+
onClick={toggleColorMode}
123+
>
124+
<ThemeIcon className="transform-transform duration-500 group-hover:rotate-12 group-hover:transition-transform group-hover:duration-500" />
125+
</Button>
126+
)}
127+
128+
{desktopScreen && (
129+
<LanguagePicker className="max-md:hidden">
130+
<Button
131+
name={DESKTOP_LANGUAGE_BUTTON_NAME}
132+
ref={languagePickerRef}
133+
variant="ghost"
134+
className="animate-fade-in gap-0 px-2 text-body transition-transform duration-500 active:bg-primary-low-contrast active:text-primary-hover data-[state='open']:bg-primary-low-contrast data-[state='open']:text-primary-hover max-md:hidden xl:px-3 [&_svg]:transition-transform [&_svg]:duration-500 [&_svg]:hover:rotate-12"
135+
>
136+
<BsTranslate className="me-2 align-middle text-2xl" />
137+
<span className="max-lg:hidden">{t("languages")}&nbsp;</span>
138+
{locale!.toUpperCase()}
139+
</Button>
140+
</LanguagePicker>
141+
)}
142+
</div>
143+
</>
144+
)
145+
}
146+
147+
ClientSideNav.displayName = "ClientSideNav"
148+
149+
export default ClientSideNav

src/components/Nav/Desktop/index.tsx

Lines changed: 0 additions & 80 deletions
This file was deleted.

src/components/Nav/Menu/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use client"
2+
13
import { BaseHTMLAttributes } from "react"
24
import { motion } from "framer-motion"
35
import {

src/components/Nav/Mobile/index.tsx

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use client"
2+
13
import {
24
Sheet,
35
SheetContent,
@@ -6,6 +8,8 @@ import {
68
SheetTrigger,
79
} from "@/components/ui/sheet"
810

11+
import { cn } from "@/lib/utils/cn"
12+
913
import { ButtonProps } from "../../ui/buttons/Button"
1014
import type { NavSections } from "../types"
1115

@@ -26,39 +30,42 @@ const MobileNavMenu = ({
2630
toggleColorMode,
2731
toggleSearch,
2832
linkSections,
33+
className,
2934
...props
3035
}: MobileNavMenuProps) => {
3136
const { isOpen, onToggle } = useDisclosure()
3237

38+
// DRAWER MENU
3339
return (
34-
<>
35-
{/* DRAWER MENU */}
36-
<Sheet open={isOpen} onOpenChange={onToggle}>
37-
<SheetTrigger asChild>
38-
<HamburgerButton className="-me-2" isMenuOpen={isOpen} {...props} />
39-
</SheetTrigger>
40-
<SheetContent side="left" className="flex flex-col" aria-describedby="">
41-
{/* HEADER ELEMENTS: SITE NAME, CLOSE BUTTON */}
42-
<SheetHeader>
43-
<MenuHeader />
44-
</SheetHeader>
40+
<Sheet open={isOpen} onOpenChange={onToggle}>
41+
<SheetTrigger asChild>
42+
<HamburgerButton
43+
className={cn("-me-2", className)}
44+
isMenuOpen={isOpen}
45+
{...props}
46+
/>
47+
</SheetTrigger>
48+
<SheetContent side="left" className="flex flex-col" aria-describedby="">
49+
{/* HEADER ELEMENTS: SITE NAME, CLOSE BUTTON */}
50+
<SheetHeader>
51+
<MenuHeader />
52+
</SheetHeader>
4553

46-
{/* MAIN NAV ACCORDION CONTENTS OF MOBILE MENU */}
47-
<div className="flex-1 overflow-auto">
48-
<MenuBody linkSections={linkSections} onToggle={onToggle} />
49-
</div>
54+
{/* MAIN NAV ACCORDION CONTENTS OF MOBILE MENU */}
55+
<div className="flex-1 overflow-auto">
56+
<MenuBody linkSections={linkSections} onToggle={onToggle} />
57+
</div>
5058

51-
{/* FOOTER ELEMENTS: SEARCH, LIGHT/DARK, LANGUAGES */}
52-
<SheetFooter className="h-[108px] justify-center border-t border-body-light px-4 py-0">
53-
<MenuFooter
54-
onToggle={onToggle}
55-
toggleSearch={toggleSearch}
56-
toggleColorMode={toggleColorMode}
57-
/>
58-
</SheetFooter>
59-
</SheetContent>
60-
</Sheet>
61-
</>
59+
{/* FOOTER ELEMENTS: SEARCH, LIGHT/DARK, LANGUAGES */}
60+
<SheetFooter className="h-[108px] justify-center border-t border-body-light px-4 py-0">
61+
<MenuFooter
62+
onToggle={onToggle}
63+
toggleSearch={toggleSearch}
64+
toggleColorMode={toggleColorMode}
65+
/>
66+
</SheetFooter>
67+
</SheetContent>
68+
</Sheet>
6269
)
6370
}
6471

0 commit comments

Comments
 (0)