Skip to content

Commit f085e00

Browse files
authored
Merge pull request #16111 from ethereum/optimize-nav
Optimize mobile nav
2 parents b022ce6 + 92ffc7f commit f085e00

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1807
-1449
lines changed

app/[locale]/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default async function LocaleLayout({
4646
// Enable static rendering
4747
setRequestLocale(locale)
4848

49-
const allMessages = await getMessages({ locale })
49+
const allMessages = await getMessages()
5050
const messages = pick(allMessages, "common")
5151

5252
const lastDeployDate = getLastDeployDate()

app/[locale]/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
157157
if (!LOCALES_CODES.includes(locale)) return notFound()
158158

159159
setRequestLocale(locale)
160+
160161
const t = await getTranslations({ locale, namespace: "page-index" })
161162
const tCommon = await getTranslations({ locale, namespace: "common" })
162163
const { direction: dir, isRtl } = getDirection(locale)

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"@radix-ui/react-accordion": "^1.2.0",
3939
"@radix-ui/react-avatar": "^1.1.2",
4040
"@radix-ui/react-checkbox": "^1.1.1",
41+
"@radix-ui/react-collapsible": "^1.1.12",
4142
"@radix-ui/react-compose-refs": "^1.1.0",
4243
"@radix-ui/react-dialog": "^1.1.1",
4344
"@radix-ui/react-dropdown-menu": "^2.1.1",

pnpm-lock.yaml

Lines changed: 60 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/ClientOnly.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"use client"
2+
3+
import { type ReactNode } from "react"
4+
5+
import { useIsClient } from "@/hooks/useIsClient"
6+
7+
type ClientOnlyProps = {
8+
children: ReactNode
9+
fallback?: ReactNode
10+
}
11+
12+
const ClientOnly = ({ children, fallback = null }: ClientOnlyProps) => {
13+
const isClient = useIsClient()
14+
15+
if (!isClient) return <>{fallback}</>
16+
return <>{children}</>
17+
}
18+
19+
export default ClientOnly
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"use client"
2+
3+
import type { LocaleDisplayInfo } from "@/lib/types"
4+
5+
import { cn } from "@/lib/utils/cn"
6+
7+
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"
8+
9+
import LanguagePicker from "."
10+
11+
import { useDisclosure } from "@/hooks/useDisclosure"
12+
import { useEventListener } from "@/hooks/useEventListener"
13+
14+
type DesktopLanguagePickerProps = {
15+
children: React.ReactNode
16+
languages: LocaleDisplayInfo[]
17+
className?: string
18+
}
19+
20+
const DesktopLanguagePicker = ({
21+
children,
22+
languages,
23+
className,
24+
}: DesktopLanguagePickerProps) => {
25+
const { isOpen, setValue, onClose, onOpen } = useDisclosure()
26+
27+
/**
28+
* Adds a keydown event listener to focus filter input (\).
29+
* @param {string} event - The keydown event.
30+
*/
31+
useEventListener("keydown", (e) => {
32+
if (e.key !== "\\" || e.metaKey || e.ctrlKey) return
33+
e.preventDefault()
34+
onOpen()
35+
})
36+
37+
return (
38+
<Popover open={isOpen} onOpenChange={setValue}>
39+
<PopoverTrigger asChild>{children}</PopoverTrigger>
40+
<PopoverContent
41+
align="end"
42+
className={cn(
43+
"flex w-[320px] flex-col bg-background-highlight p-0",
44+
className
45+
)}
46+
>
47+
<LanguagePicker
48+
className="max-h-[calc(100vh-12rem)]"
49+
languages={languages}
50+
onSelect={onClose}
51+
onNoResultsClose={onClose}
52+
onTranslationProgramClick={onClose}
53+
/>
54+
</PopoverContent>
55+
</Popover>
56+
)
57+
}
58+
59+
export default DesktopLanguagePicker
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { useLocale } from "next-intl"
2+
3+
import type { LocaleDisplayInfo } from "@/lib/types"
4+
5+
import { ButtonLink } from "@/components/ui/buttons/Button"
6+
7+
import { DEFAULT_LOCALE } from "@/lib/constants"
8+
9+
import { useTranslation } from "@/hooks/useTranslation"
10+
11+
type LanguagePickerFooterProps = {
12+
intlLanguagePreference?: LocaleDisplayInfo
13+
onTranslationProgramClick: () => void
14+
}
15+
16+
const LanguagePickerFooter = ({
17+
intlLanguagePreference,
18+
onTranslationProgramClick,
19+
}: LanguagePickerFooterProps) => {
20+
const { t } = useTranslation("common")
21+
const locale = useLocale()
22+
return (
23+
<div className="sticky bottom-0 flex border-t-2 border-primary bg-primary-low-contrast p-0 pb-1 pt-1">
24+
<div className="flex w-full items-center justify-between px-4">
25+
<div className="flex min-w-0 flex-col items-start">
26+
{locale === DEFAULT_LOCALE ? (
27+
<p className="overflow-hidden text-ellipsis whitespace-nowrap text-xs font-bold text-body">
28+
{intlLanguagePreference
29+
? `${t("page-languages-translate-cta-title")} ${t(`language-${intlLanguagePreference.localeOption}`)}`
30+
: "Translate ethereum.org"}
31+
</p>
32+
) : (
33+
<p className="overflow-hidden text-ellipsis whitespace-nowrap text-xs font-bold text-body">
34+
{t("page-languages-translate-cta-title")}{" "}
35+
{t(`language-${locale}`)}
36+
</p>
37+
)}
38+
<p className="text-xs text-body">
39+
{t("page-languages-recruit-community")}
40+
</p>
41+
</div>
42+
<ButtonLink
43+
className="text-nowrap"
44+
href="/contributing/translation-program/"
45+
size="sm"
46+
onClick={onTranslationProgramClick}
47+
>
48+
{t("get-involved")}
49+
</ButtonLink>
50+
</div>
51+
</div>
52+
)
53+
}
54+
55+
export default LanguagePickerFooter
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import type { LocaleDisplayInfo } from "@/lib/types"
2+
3+
import {
4+
Command,
5+
CommandEmpty,
6+
CommandGroup,
7+
CommandInput,
8+
CommandList,
9+
} from "../ui/command"
10+
11+
import MenuItem from "./MenuItem"
12+
import NoResultsCallout from "./NoResultsCallout"
13+
14+
import { useTranslation } from "@/hooks/useTranslation"
15+
16+
type LanguagePickerMenuProps = {
17+
className?: string
18+
languages: LocaleDisplayInfo[]
19+
onClose: () => void
20+
onSelect: (value: string) => void
21+
}
22+
23+
const LanguagePickerMenu = ({
24+
className,
25+
languages,
26+
onClose,
27+
onSelect,
28+
}: LanguagePickerMenuProps) => {
29+
const { t } = useTranslation("common")
30+
31+
return (
32+
<Command
33+
className={className}
34+
filter={(value: string, search: string) => {
35+
const item = languages.find((name) => name.localeOption === value)
36+
37+
if (!item) return 0
38+
39+
const { localeOption, sourceName, targetName, englishName } = item
40+
41+
if (
42+
(localeOption + sourceName + targetName + englishName)
43+
.toLowerCase()
44+
.includes(search.toLowerCase())
45+
) {
46+
return 1
47+
}
48+
49+
return 0
50+
}}
51+
>
52+
<div className="text-xs text-body-medium">
53+
{t("page-languages-filter-label")}{" "}
54+
<span className="lowercase">
55+
({languages.length} {t("common:languages")})
56+
</span>
57+
</div>
58+
59+
<CommandInput
60+
placeholder={t("page-languages-filter-placeholder")}
61+
className="h-9"
62+
kbdShortcut="\"
63+
data-testid="language-filter-input"
64+
/>
65+
66+
<CommandList className="max-h-full">
67+
<CommandEmpty className="py-0 text-left text-base">
68+
<NoResultsCallout onClose={onClose} />
69+
</CommandEmpty>
70+
<CommandGroup className="p-0">
71+
{languages.map((displayInfo) => (
72+
<MenuItem
73+
key={"item-" + displayInfo.localeOption}
74+
displayInfo={displayInfo}
75+
onSelect={onSelect}
76+
data-testid={`language-option-${displayInfo.localeOption}`}
77+
/>
78+
))}
79+
</CommandGroup>
80+
</CommandList>
81+
</Command>
82+
)
83+
}
84+
85+
export default LanguagePickerMenu

src/components/LanguagePicker/MenuItem.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,13 @@ const MenuItem = ({ displayInfo, ...props }: ItemProps) => {
2222
sourceName,
2323
targetName,
2424
approvalProgress,
25-
wordsApproved,
25+
progress,
26+
words,
2627
} = displayInfo
2728
const { t } = useTranslation("common")
2829
const locale = useLocale()
2930
const isCurrent = localeOption === locale
3031

31-
const getProgressInfo = (approvalProgress: number, wordsApproved: number) => {
32-
const percentage = new Intl.NumberFormat(locale!, {
33-
style: "percent",
34-
}).format(approvalProgress / 100)
35-
const progress =
36-
approvalProgress === 0 ? "<" + percentage.replace("0", "1") : percentage
37-
const words = new Intl.NumberFormat(locale!).format(wordsApproved)
38-
return { progress, words }
39-
}
40-
41-
const { progress, words } = getProgressInfo(approvalProgress, wordsApproved)
42-
4332
return (
4433
<CommandItem
4534
value={localeOption}

0 commit comments

Comments
 (0)