mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-07-27 20:25:10 +00:00
UI: Support custom renderer for title in layouts
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'fumadocs-ui': patch
|
||||
'@fumadocs/base-ui': patch
|
||||
---
|
||||
|
||||
Support custom renderer for `title` in layouts
|
||||
@@ -18,7 +18,11 @@ import {
|
||||
SidebarTrigger,
|
||||
SidebarViewport,
|
||||
} from './sidebar';
|
||||
import { type BaseLayoutProps, resolveLinkItems } from '@/layouts/shared';
|
||||
import {
|
||||
type BaseLayoutProps,
|
||||
renderTitleNav,
|
||||
resolveLinkItems,
|
||||
} from '@/layouts/shared';
|
||||
import { LinkItem } from '@fumadocs/ui/link-item';
|
||||
import {
|
||||
LanguageToggle,
|
||||
@@ -32,7 +36,6 @@ import {
|
||||
} from './client';
|
||||
import { TreeContextProvider } from '@/contexts/tree';
|
||||
import { ThemeToggle } from '../shared/theme-toggle';
|
||||
import Link from 'fumadocs-core/link';
|
||||
import {
|
||||
LargeSearchToggle,
|
||||
SearchToggle,
|
||||
@@ -147,12 +150,10 @@ export function DocsLayout({
|
||||
<SidebarContent {...rest}>
|
||||
<div className="flex flex-col gap-3 p-4 pb-2">
|
||||
<div className="flex">
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className="inline-flex text-[0.9375rem] items-center gap-2.5 font-medium me-auto"
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
{renderTitleNav(nav, {
|
||||
className:
|
||||
'inline-flex text-[0.9375rem] items-center gap-2.5 font-medium me-auto',
|
||||
})}
|
||||
{nav.children}
|
||||
{collapsible && (
|
||||
<SidebarCollapseTrigger
|
||||
@@ -279,12 +280,9 @@ export function DocsLayout({
|
||||
id="nd-subnav"
|
||||
className="[grid-area:header] sticky top-(--fd-docs-row-1) z-30 flex items-center ps-4 pe-2.5 border-b transition-colors backdrop-blur-sm h-(--fd-header-height) md:hidden max-md:layout:[--fd-header-height:--spacing(14)] data-[transparent=false]:bg-fd-background/80"
|
||||
>
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className="inline-flex items-center gap-2.5 font-semibold"
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
{renderTitleNav(nav, {
|
||||
className: 'inline-flex items-center gap-2.5 font-semibold',
|
||||
})}
|
||||
<div className="flex-1">{nav.children}</div>
|
||||
{searchToggle.enabled !== false &&
|
||||
(searchToggle.components?.sm ?? (
|
||||
|
||||
@@ -15,6 +15,7 @@ import { cn } from '@fumadocs/ui/cn';
|
||||
import {
|
||||
type LinkItemType,
|
||||
type NavOptions,
|
||||
renderTitleNav,
|
||||
resolveLinkItems,
|
||||
} from '@/layouts/shared';
|
||||
import { LinkItem } from '@fumadocs/ui/link-item';
|
||||
@@ -107,12 +108,9 @@ export function Header({
|
||||
className={cn(s.open && 'shadow-lg rounded-b-2xl')}
|
||||
>
|
||||
<NavigationMenuList className="flex h-14 w-full items-center px-4">
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className="inline-flex items-center gap-2.5 font-semibold"
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
{renderTitleNav(nav, {
|
||||
className: 'inline-flex items-center gap-2.5 font-semibold',
|
||||
})}
|
||||
{nav.children}
|
||||
<ul className="flex flex-row items-center gap-2 px-6 max-sm:hidden">
|
||||
{navItems
|
||||
|
||||
@@ -5,7 +5,11 @@ import {
|
||||
type ReactNode,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import { type BaseLayoutProps, resolveLinkItems } from '@/layouts/shared';
|
||||
import {
|
||||
type BaseLayoutProps,
|
||||
renderTitleNav,
|
||||
resolveLinkItems,
|
||||
} from '@/layouts/shared';
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarCollapseTrigger,
|
||||
@@ -30,7 +34,6 @@ import {
|
||||
LayoutHeaderTabs,
|
||||
NavbarLinkItem,
|
||||
} from '@/layouts/notebook/client';
|
||||
import Link from 'fumadocs-core/link';
|
||||
import {
|
||||
LargeSearchToggle,
|
||||
SearchToggle,
|
||||
@@ -177,12 +180,9 @@ export function DocsLayout(props: DocsLayoutProps) {
|
||||
<Header>
|
||||
{navMode === 'auto' && (
|
||||
<div className="flex justify-between">
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className="inline-flex items-center gap-2.5 font-medium"
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
{renderTitleNav(nav, {
|
||||
className: 'inline-flex items-center gap-2.5 font-medium',
|
||||
})}
|
||||
{collapsible && (
|
||||
<SidebarCollapseTrigger
|
||||
className={cn(
|
||||
@@ -349,15 +349,12 @@ function DocsNavbar({
|
||||
<SidebarIcon />
|
||||
</SidebarCollapseTrigger>
|
||||
)}
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className={cn(
|
||||
{renderTitleNav(nav, {
|
||||
className: cn(
|
||||
'inline-flex items-center gap-2.5 font-semibold',
|
||||
navMode === 'auto' && 'md:hidden',
|
||||
)}
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
),
|
||||
})}
|
||||
</div>
|
||||
{searchToggle.enabled !== false &&
|
||||
(searchToggle.components?.lg ? (
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
import type { I18nConfig } from 'fumadocs-core/i18n';
|
||||
import type { LinkItemType } from '@fumadocs/ui/link-item';
|
||||
import Link from 'fumadocs-core/link';
|
||||
|
||||
export interface NavOptions {
|
||||
enabled: boolean;
|
||||
component: ReactNode;
|
||||
|
||||
title?: ReactNode;
|
||||
title?: ReactNode | ((props: ComponentProps<'a'>) => ReactNode);
|
||||
|
||||
/**
|
||||
* Redirect url of title
|
||||
@@ -86,4 +87,16 @@ export function resolveLinkItems({
|
||||
return result;
|
||||
}
|
||||
|
||||
export function renderTitleNav(
|
||||
{ title, url = '/' }: Partial<NavOptions>,
|
||||
props: ComponentProps<'a'>,
|
||||
) {
|
||||
if (typeof title === 'function') return title({ href: url, ...props });
|
||||
return (
|
||||
<Link href={url} {...props}>
|
||||
{title}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
export type * from '@fumadocs/ui/link-item';
|
||||
|
||||
@@ -18,7 +18,11 @@ import {
|
||||
SidebarTrigger,
|
||||
SidebarViewport,
|
||||
} from './sidebar';
|
||||
import { type BaseLayoutProps, resolveLinkItems } from '@/layouts/shared';
|
||||
import {
|
||||
type BaseLayoutProps,
|
||||
renderTitleNav,
|
||||
resolveLinkItems,
|
||||
} from '@/layouts/shared';
|
||||
import { LinkItem } from '@fumadocs/ui/link-item';
|
||||
import {
|
||||
LanguageToggle,
|
||||
@@ -32,7 +36,6 @@ import {
|
||||
} from './client';
|
||||
import { TreeContextProvider } from '@/contexts/tree';
|
||||
import { ThemeToggle } from '../shared/theme-toggle';
|
||||
import Link from 'fumadocs-core/link';
|
||||
import {
|
||||
LargeSearchToggle,
|
||||
SearchToggle,
|
||||
@@ -147,12 +150,10 @@ export function DocsLayout({
|
||||
<SidebarContent {...rest}>
|
||||
<div className="flex flex-col gap-3 p-4 pb-2">
|
||||
<div className="flex">
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className="inline-flex text-[0.9375rem] items-center gap-2.5 font-medium me-auto"
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
{renderTitleNav(nav, {
|
||||
className:
|
||||
'inline-flex text-[0.9375rem] items-center gap-2.5 font-medium me-auto',
|
||||
})}
|
||||
{nav.children}
|
||||
{collapsible && (
|
||||
<SidebarCollapseTrigger
|
||||
@@ -279,12 +280,9 @@ export function DocsLayout({
|
||||
id="nd-subnav"
|
||||
className="[grid-area:header] sticky top-(--fd-docs-row-1) z-30 flex items-center ps-4 pe-2.5 border-b transition-colors backdrop-blur-sm h-(--fd-header-height) md:hidden max-md:layout:[--fd-header-height:--spacing(14)] data-[transparent=false]:bg-fd-background/80"
|
||||
>
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className="inline-flex items-center gap-2.5 font-semibold"
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
{renderTitleNav(nav, {
|
||||
className: 'inline-flex items-center gap-2.5 font-semibold',
|
||||
})}
|
||||
<div className="flex-1">{nav.children}</div>
|
||||
{searchToggle.enabled !== false &&
|
||||
(searchToggle.components?.sm ?? (
|
||||
|
||||
@@ -6,6 +6,7 @@ import { cn } from '@fumadocs/ui/cn';
|
||||
import {
|
||||
type LinkItemType,
|
||||
type NavOptions,
|
||||
renderTitleNav,
|
||||
resolveLinkItems,
|
||||
} from '@/layouts/shared';
|
||||
import { LinkItem } from '@fumadocs/ui/link-item';
|
||||
@@ -82,12 +83,9 @@ export function Header({
|
||||
|
||||
return (
|
||||
<HeaderNavigationMenu transparentMode={nav.transparentMode}>
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className="inline-flex items-center gap-2.5 font-semibold"
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
{renderTitleNav(nav, {
|
||||
className: 'inline-flex items-center gap-2.5 font-semibold',
|
||||
})}
|
||||
{nav.children}
|
||||
<ul className="flex flex-row items-center gap-2 px-6 max-sm:hidden">
|
||||
{navItems
|
||||
|
||||
@@ -5,7 +5,11 @@ import {
|
||||
type ReactNode,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import { type BaseLayoutProps, resolveLinkItems } from '@/layouts/shared';
|
||||
import {
|
||||
type BaseLayoutProps,
|
||||
renderTitleNav,
|
||||
resolveLinkItems,
|
||||
} from '@/layouts/shared';
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarCollapseTrigger,
|
||||
@@ -30,7 +34,6 @@ import {
|
||||
LayoutHeaderTabs,
|
||||
NavbarLinkItem,
|
||||
} from '@/layouts/notebook/client';
|
||||
import Link from 'fumadocs-core/link';
|
||||
import {
|
||||
LargeSearchToggle,
|
||||
SearchToggle,
|
||||
@@ -177,12 +180,9 @@ export function DocsLayout(props: DocsLayoutProps) {
|
||||
<Header>
|
||||
{navMode === 'auto' && (
|
||||
<div className="flex justify-between">
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className="inline-flex items-center gap-2.5 font-medium"
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
{renderTitleNav(nav, {
|
||||
className: 'inline-flex items-center gap-2.5 font-medium',
|
||||
})}
|
||||
{collapsible && (
|
||||
<SidebarCollapseTrigger
|
||||
className={cn(
|
||||
@@ -349,15 +349,12 @@ function DocsNavbar({
|
||||
<SidebarIcon />
|
||||
</SidebarCollapseTrigger>
|
||||
)}
|
||||
<Link
|
||||
href={nav.url ?? '/'}
|
||||
className={cn(
|
||||
{renderTitleNav(nav, {
|
||||
className: cn(
|
||||
'inline-flex items-center gap-2.5 font-semibold',
|
||||
navMode === 'auto' && 'md:hidden',
|
||||
)}
|
||||
>
|
||||
{nav.title}
|
||||
</Link>
|
||||
),
|
||||
})}
|
||||
</div>
|
||||
{searchToggle.enabled !== false &&
|
||||
(searchToggle.components?.lg ? (
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
import type { I18nConfig } from 'fumadocs-core/i18n';
|
||||
import type { LinkItemType } from '@fumadocs/ui/link-item';
|
||||
import Link from 'fumadocs-core/link';
|
||||
|
||||
export interface NavOptions {
|
||||
enabled: boolean;
|
||||
component: ReactNode;
|
||||
|
||||
title?: ReactNode;
|
||||
title?: ReactNode | ((props: ComponentProps<'a'>) => ReactNode);
|
||||
|
||||
/**
|
||||
* Redirect url of title
|
||||
@@ -86,4 +87,16 @@ export function resolveLinkItems({
|
||||
return result;
|
||||
}
|
||||
|
||||
export function renderTitleNav(
|
||||
{ title, url = '/' }: Partial<NavOptions>,
|
||||
props: ComponentProps<'a'>,
|
||||
) {
|
||||
if (typeof title === 'function') return title({ href: url, ...props });
|
||||
return (
|
||||
<Link href={url} {...props}>
|
||||
{title}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
export type * from '@fumadocs/ui/link-item';
|
||||
|
||||
Reference in New Issue
Block a user