mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
UI: Support disableThemeSwitch on layouts
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-ui': minor
|
||||
---
|
||||
|
||||
Support `disableThemeSwitch` on layouts
|
||||
@@ -66,6 +66,7 @@ export const docsOptions: DocsLayoutProps = {
|
||||
transparentMode: 'none',
|
||||
children: undefined,
|
||||
},
|
||||
links: baseOptions.links?.slice(1),
|
||||
sidebar: {
|
||||
banner: (
|
||||
<RootToggle
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { SidebarTrigger } from 'fumadocs-core/sidebar';
|
||||
import { Menu, SidebarIcon, X } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { ButtonHTMLAttributes, useCallback } from 'react';
|
||||
import { useSidebar } from '@/contexts/sidebar';
|
||||
import { useSearchContext } from '@/contexts/search';
|
||||
import { SearchToggle } from '@/components/layout/search-toggle';
|
||||
@@ -45,18 +45,21 @@ export function SubNav({
|
||||
);
|
||||
}
|
||||
|
||||
export function SidebarCollapseTrigger(): React.ReactElement {
|
||||
export function SidebarCollapseTrigger(
|
||||
props: ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
): React.ReactElement {
|
||||
const { setCollapsed } = useSidebar();
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Collapse Sidebar"
|
||||
{...props}
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
color: 'ghost',
|
||||
size: 'icon',
|
||||
className: 'ms-auto max-md:hidden',
|
||||
className: props.className,
|
||||
}),
|
||||
)}
|
||||
onClick={useCallback(() => {
|
||||
@@ -68,7 +71,7 @@ export function SidebarCollapseTrigger(): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
export { LinksMenu } from '@/components/layout/link-item';
|
||||
export { LinksMenu, LinkItem } from '@/components/layout/link-item';
|
||||
export { Sidebar } from '@/components/layout/sidebar';
|
||||
export { TreeContextProvider } from '@/contexts/tree';
|
||||
export { ThemeToggle } from '@/components/layout/theme-toggle';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PageTree } from 'fumadocs-core/server';
|
||||
import type { ReactNode, HTMLAttributes } from 'react';
|
||||
import { ReactNode, HTMLAttributes, Fragment } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { MoreHorizontal } from 'lucide-react';
|
||||
import { notFound } from 'next/navigation';
|
||||
@@ -17,6 +17,7 @@ declare const {
|
||||
SubNav,
|
||||
LanguageToggle,
|
||||
LinksMenu,
|
||||
LinkItem,
|
||||
DynamicSidebar,
|
||||
Sidebar,
|
||||
}: typeof import('./docs.client');
|
||||
@@ -46,7 +47,6 @@ export function DocsLayout({
|
||||
component: sidebarReplace,
|
||||
...sidebar
|
||||
} = {},
|
||||
containerProps = {},
|
||||
i18n = false,
|
||||
...props
|
||||
}: DocsLayoutProps): React.ReactNode {
|
||||
@@ -87,14 +87,34 @@ export function DocsLayout({
|
||||
</LinksMenu>,
|
||||
);
|
||||
|
||||
footer.push(<ThemeToggle key="theme" />);
|
||||
if (sidebar.footer) {
|
||||
footer.push(<Fragment key="footer">{sidebar.footer}</Fragment>);
|
||||
}
|
||||
|
||||
if (!props.disableThemeSwitch) {
|
||||
footer.push(<ThemeToggle key="theme" className="me-auto" />);
|
||||
}
|
||||
|
||||
if (i18n) {
|
||||
footer.push(<LanguageToggle key="i18n" />);
|
||||
}
|
||||
|
||||
if (links.some((v) => v.type === 'icon')) {
|
||||
footer.push(
|
||||
<Fragment key="links">
|
||||
{links
|
||||
.filter((v) => v.type === 'icon')
|
||||
.map((v, i) => (
|
||||
<LinkItem key={i} item={v} on="nav" className="md:hidden" />
|
||||
))}
|
||||
</Fragment>,
|
||||
);
|
||||
}
|
||||
|
||||
if (collapsible) {
|
||||
footer.push(<SidebarCollapseTrigger key="sidebar" />);
|
||||
footer.push(
|
||||
<SidebarCollapseTrigger key="sidebar" className="max-md:hidden" />,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -102,14 +122,14 @@ export function DocsLayout({
|
||||
{replaceOrDefault(nav, <SubNav {...nav} />)}
|
||||
<main
|
||||
id="nd-docs-layout"
|
||||
{...containerProps}
|
||||
className={cn('flex flex-1 flex-row', containerProps.className)}
|
||||
{...props.containerProps}
|
||||
className={cn('flex flex-1 flex-row', props.containerProps?.className)}
|
||||
>
|
||||
{replaceOrDefault(
|
||||
{ enabled: sidebarEnabled, component: sidebarReplace },
|
||||
<Aside
|
||||
{...sidebar}
|
||||
items={links}
|
||||
items={links.filter((v) => v.type !== 'icon')}
|
||||
banner={
|
||||
banner.length > 0 || sidebar.banner ? (
|
||||
<>
|
||||
@@ -129,14 +149,7 @@ export function DocsLayout({
|
||||
sidebar.bannerProps?.className,
|
||||
),
|
||||
}}
|
||||
footer={
|
||||
footer.length > 0 || sidebar.footer ? (
|
||||
<>
|
||||
{sidebar.footer}
|
||||
{footer}
|
||||
</>
|
||||
) : null
|
||||
}
|
||||
footer={footer.length > 0 ? footer : null}
|
||||
/>,
|
||||
)}
|
||||
{props.children}
|
||||
|
||||
@@ -20,14 +20,11 @@ import { LanguageToggle } from '@/components/layout/language-toggle';
|
||||
import type { SharedNavProps } from './shared';
|
||||
|
||||
export function Nav({
|
||||
title,
|
||||
url,
|
||||
items,
|
||||
transparentMode,
|
||||
enableSearch = true,
|
||||
i18n,
|
||||
children,
|
||||
...props
|
||||
}: SharedNavProps & {
|
||||
disableThemeSwitch?: boolean;
|
||||
i18n?: boolean;
|
||||
items: LinkItemType[];
|
||||
}): React.ReactElement {
|
||||
@@ -35,10 +32,14 @@ export function Nav({
|
||||
const { text } = useI18n();
|
||||
|
||||
return (
|
||||
<NavBox id="nd-nav" className="h-14" transparentMode={transparentMode}>
|
||||
<NavBox
|
||||
id="nd-nav"
|
||||
className="h-14"
|
||||
transparentMode={props.transparentMode}
|
||||
>
|
||||
<nav className="mx-auto flex size-full max-w-container flex-row items-center gap-6 px-4">
|
||||
<Title title={title} url={url} />
|
||||
{children}
|
||||
<Title title={props.title} url={props.url} />
|
||||
{props.children}
|
||||
{items
|
||||
.filter((item) => !isSecondary(item))
|
||||
.map((item, i) => (
|
||||
@@ -68,13 +69,15 @@ export function Nav({
|
||||
)}
|
||||
footer={
|
||||
<>
|
||||
<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>
|
||||
{i18n ? (
|
||||
{!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}
|
||||
|
||||
@@ -8,21 +8,24 @@ export type HomeLayoutProps = BaseLayoutProps;
|
||||
export function HomeLayout({
|
||||
nav = {},
|
||||
links = [],
|
||||
githubUrl,
|
||||
i18n,
|
||||
children,
|
||||
...props
|
||||
}: BaseLayoutProps): React.ReactElement {
|
||||
const finalLinks = getLinks(links, githubUrl);
|
||||
const finalLinks = getLinks(links, props.githubUrl);
|
||||
|
||||
return (
|
||||
<>
|
||||
{replaceOrDefault(
|
||||
nav,
|
||||
<Nav items={finalLinks} i18n={i18n} {...nav}>
|
||||
<Nav
|
||||
items={finalLinks}
|
||||
i18n={props.i18n}
|
||||
disableThemeSwitch={props.disableThemeSwitch}
|
||||
{...nav}
|
||||
>
|
||||
{nav.children}
|
||||
</Nav>,
|
||||
)}
|
||||
{children}
|
||||
{props.children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ export interface SharedNavProps extends TitleProps, NavBoxProps {
|
||||
}
|
||||
|
||||
export interface BaseLayoutProps {
|
||||
/**
|
||||
* Remove theme switcher component
|
||||
*/
|
||||
disableThemeSwitch?: boolean;
|
||||
|
||||
/**
|
||||
* Enable Language Switch
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user