UI: Show i18n language toggle on home layout

This commit is contained in:
fuma-nama
2024-09-25 18:30:52 +08:00
parent e8392cb42b
commit ad47fd8c27
7 changed files with 74 additions and 36 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-ui': minor
---
Show i18n language toggle on home layout
+7
View File
@@ -5,4 +5,11 @@ export const baseOptions: BaseLayoutProps = {
nav: {
title: 'I18n Docs',
},
links: [
{
type: 'main',
text: 'Documentation',
url: '/docs',
},
],
};
@@ -1,7 +1,5 @@
'use client';
import { useState } from 'react';
import type { PopoverProps } from '@radix-ui/react-popover';
import { LanguagesIcon } from 'lucide-react';
import { type ButtonHTMLAttributes, type HTMLAttributes } from 'react';
import { useI18n } from '@/contexts/i18n';
import {
Popover,
@@ -11,22 +9,28 @@ import {
import { cn } from '@/utils/cn';
import { buttonVariants } from '@/components/ui/button';
export type LanguageSelectProps = Omit<PopoverProps, 'open' | 'onOpenChange'>;
export type LanguageSelectProps = ButtonHTMLAttributes<HTMLButtonElement>;
export function LanguageToggle(props: LanguageSelectProps): React.ReactElement {
const context = useI18n();
const [open, setOpen] = useState(false);
if (!context.locales) throw new Error('Missing `<I18nProvider />`');
return (
<Popover open={open} onOpenChange={setOpen} {...props}>
<Popover>
<PopoverTrigger
aria-label={context.text.chooseLanguage}
className={cn(buttonVariants({ size: 'icon', color: 'ghost' }))}
{...props}
className={cn(
buttonVariants({
color: 'ghost',
className: 'gap-1.5 p-1.5',
}),
props.className,
)}
>
<LanguagesIcon />
{props.children}
</PopoverTrigger>
<PopoverContent className="flex flex-col p-1">
<PopoverContent className="flex flex-col overflow-hidden p-0">
<p className="mb-1 p-2 text-xs font-medium text-fd-muted-foreground">
{context.text.chooseLanguage}
</p>
@@ -35,7 +39,7 @@ export function LanguageToggle(props: LanguageSelectProps): React.ReactElement {
key={item.locale}
type="button"
className={cn(
'rounded-md p-2 text-left text-sm transition-colors duration-100',
'p-2 text-start text-sm',
item.locale === context.locale
? 'bg-fd-primary/10 font-medium text-fd-primary'
: 'hover:bg-fd-accent hover:text-fd-accent-foreground',
@@ -51,3 +55,14 @@ export function LanguageToggle(props: LanguageSelectProps): React.ReactElement {
</Popover>
);
}
export function LanguageToggleText(
props: HTMLAttributes<HTMLSpanElement>,
): React.ReactElement {
const context = useI18n();
const text = context.locales?.find(
(item) => item.locale === context.locale,
)?.name;
return <span {...props}>{text}</span>;
}
@@ -236,7 +236,7 @@ export function LinksMenu({
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger {...props} />
<PopoverContent className="flex flex-col">
<PopoverContent className="flex flex-col p-1">
{items.map((item, i) => (
<LinkItem key={i} item={item} on="menu" />
))}
+4 -1
View File
@@ -81,5 +81,8 @@ export { RootToggle } from '@/components/layout/root-toggle';
export { Sidebar } from '@/components/layout/sidebar';
export { TreeContextProvider } from '@/contexts/tree';
export { ThemeToggle } from '@/components/layout/theme-toggle';
export { LanguageToggle } from '@/components/layout/language-toggle';
export {
LanguageToggle,
LanguageToggleText,
} from '@/components/layout/language-toggle';
export { DynamicSidebar } from '@/components/layout/dynamic-sidebar';
+8 -2
View File
@@ -1,7 +1,7 @@
import type { PageTree } from 'fumadocs-core/server';
import { ReactNode, HTMLAttributes, Fragment } from 'react';
import Link from 'next/link';
import { MoreHorizontal } from 'lucide-react';
import { Languages, MoreHorizontal } from 'lucide-react';
import { notFound } from 'next/navigation';
import { cn } from '@/utils/cn';
import { buttonVariants } from '@/components/ui/button';
@@ -18,6 +18,7 @@ declare const {
ThemeToggle,
SubNav,
LanguageToggle,
LanguageToggleText,
LinksMenu,
RootToggle,
LinkItem,
@@ -104,7 +105,12 @@ export function DocsLayout({
}
if (i18n) {
footer.push(<LanguageToggle key="i18n" />);
footer.push(
<LanguageToggle key="i18n">
<Languages className="size-5" />
<LanguageToggleText className="md:hidden" />
</LanguageToggle>,
);
}
if (links.some((v) => v.type === 'icon')) {
+24 -22
View File
@@ -1,8 +1,7 @@
'use client';
import { MoreVertical } from 'lucide-react';
import { ChevronDown, Languages, MoreVertical } from 'lucide-react';
import { useSearchContext } from '@/contexts/search';
import { useI18n } from '@/contexts/i18n';
import {
LinkItem,
type LinkItemType,
@@ -16,7 +15,10 @@ import { ThemeToggle } from '@/components/layout/theme-toggle';
import { NavBox, Title } from '@/components/layout/nav';
import { cn } from '@/utils/cn';
import { buttonVariants } from '@/components/ui/button';
import { LanguageToggle } from '@/components/layout/language-toggle';
import {
LanguageToggle,
LanguageToggleText,
} from '@/components/layout/language-toggle';
import type { SharedNavProps } from './shared';
export function Nav({
@@ -29,7 +31,6 @@ export function Nav({
items: LinkItemType[];
}): React.ReactElement {
const search = useSearchContext();
const { text } = useI18n();
return (
<NavBox
@@ -54,6 +55,11 @@ export function Nav({
) : null}
<ThemeToggle className="max-lg:hidden" />
{props.i18n ? (
<LanguageToggle className="max-lg:hidden">
<Languages className="size-5" />
</LanguageToggle>
) : null}
{items.filter(isSecondary).map((item, i) => (
<LinkItem key={i} item={item} className="max-lg:hidden" />
))}
@@ -68,24 +74,20 @@ export function Nav({
}),
)}
footer={
<>
{!props.disableThemeSwitch ? (
<div className="flex flex-row items-center justify-between px-2 pt-2">
<p className="font-medium text-fd-muted-foreground">
{text.chooseTheme}
</p>
<ThemeToggle />
</div>
) : null}
{props.i18n ? (
<div className="flex flex-row items-center justify-between px-2 pt-2">
<p className="font-medium text-fd-muted-foreground">
{text.chooseLanguage}
</p>
<LanguageToggle />
</div>
) : null}
</>
Boolean(props.i18n) || !props.disableThemeSwitch ? (
<div className="flex flex-row items-center gap-1.5 px-2 pt-1.5">
{props.i18n ? (
<LanguageToggle className="-ms-1.5">
<Languages className="size-5" />
<LanguageToggleText />
<ChevronDown className="size-3 text-fd-muted-foreground" />
</LanguageToggle>
) : null}
{!props.disableThemeSwitch ? (
<ThemeToggle className="ms-auto" />
) : null}
</div>
) : null
}
>
<MoreVertical />