mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
UI: move certain logic from page to layouts
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-ui': patch
|
||||
---
|
||||
|
||||
improve notebook layout for transparent sidebar
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EslintConfiguration">
|
||||
<option name="fix-on-save" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -63,6 +63,9 @@ export default async function Page(props: {
|
||||
sha: 'dev',
|
||||
path,
|
||||
}}
|
||||
article={{
|
||||
className: 'max-sm:pb-16',
|
||||
}}
|
||||
>
|
||||
<DocsTitle>{page.data.title}</DocsTitle>
|
||||
<DocsDescription>{page.data.description}</DocsDescription>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DocsLayout, type DocsLayoutProps } from 'fumadocs-ui/layouts/docs';
|
||||
import { DocsLayout, type DocsLayoutProps } from 'fumadocs-ui/layouts/notebook';
|
||||
import type { ReactNode } from 'react';
|
||||
import { MessageCircle } from 'lucide-react';
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
|
||||
@@ -15,11 +15,16 @@
|
||||
}
|
||||
|
||||
:root {
|
||||
--fd-layout-width: 1400px;
|
||||
--headless-color: 250 80% 54%;
|
||||
--mdx-color: 0 0% 9%;
|
||||
--ui-color: 220deg 91% 54%;
|
||||
}
|
||||
|
||||
body {
|
||||
overscroll-behavior-y: none;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--headless-color: 250 100% 80%;
|
||||
--mdx-color: 0 0% 100%;
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "eslint.config.mjs"]
|
||||
"exclude": ["node_modules", "dist", "eslint.config.mjs", "tailwind.config.js"]
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export function SearchDialog({
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogOverlay className="fixed inset-0 z-50 bg-fd-background/50 backdrop-blur-sm data-[state=closed]:animate-fd-fade-out data-[state=open]:animate-fd-fade-in" />
|
||||
<DialogOverlay className="fixed inset-0 z-50 bg-black/30 backdrop-blur-sm data-[state=closed]:animate-fd-fade-out data-[state=open]:animate-fd-fade-in" />
|
||||
<DialogContent
|
||||
aria-describedby={undefined}
|
||||
className="fixed left-1/2 top-[10vh] z-50 w-[98vw] max-w-screen-sm origin-left -translate-x-1/2 rounded-lg border bg-fd-popover text-fd-popover-foreground shadow-lg data-[state=closed]:animate-fd-dialog-out data-[state=open]:animate-fd-dialog-in"
|
||||
@@ -274,7 +274,8 @@ function CommandItem({
|
||||
onPointerMove={() => onActiveChange(value)}
|
||||
{...props}
|
||||
className={cn(
|
||||
'flex min-h-10 select-none flex-row items-center gap-2.5 rounded-lg px-2 text-start text-sm aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-selected:bg-fd-accent aria-selected:text-fd-accent-foreground',
|
||||
'flex min-h-10 select-none flex-row items-center gap-2.5 rounded-lg px-2 text-start text-sm',
|
||||
active === value && 'bg-fd-accent text-fd-accent-foreground',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
'use client';
|
||||
import { useMemo } from 'react';
|
||||
import { cn } from '@/utils/cn';
|
||||
import type { TOCItemType } from 'fumadocs-core/server';
|
||||
import { useI18n } from '@/contexts/i18n';
|
||||
import * as Primitive from 'fumadocs-core/toc';
|
||||
import { ChevronRight, Text } from 'lucide-react';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import type {
|
||||
PopoverContentProps,
|
||||
PopoverTriggerProps,
|
||||
} from '@radix-ui/react-popover';
|
||||
|
||||
export const TocPopover = Popover;
|
||||
|
||||
export function TocPopoverTrigger({
|
||||
items,
|
||||
...props
|
||||
}: PopoverTriggerProps & { items: TOCItemType[] }) {
|
||||
const { text } = useI18n();
|
||||
const active = Primitive.useActiveAnchor();
|
||||
const current = useMemo(() => {
|
||||
return items.find((item) => active === item.url.slice(1))?.title;
|
||||
}, [items, active]);
|
||||
|
||||
return (
|
||||
<PopoverTrigger
|
||||
{...props}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-2 text-nowrap px-4 py-2 text-start',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
<Text className="size-4 shrink-0" />
|
||||
{text.toc}
|
||||
{current ? (
|
||||
<>
|
||||
<ChevronRight className="-mx-1.5 size-4 shrink-0 text-fd-muted-foreground" />
|
||||
<span className="truncate text-fd-muted-foreground">{current}</span>
|
||||
</>
|
||||
) : null}
|
||||
</PopoverTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
export function TocPopoverContent(props: PopoverContentProps) {
|
||||
return (
|
||||
<PopoverContent
|
||||
hideWhenDetached
|
||||
alignOffset={16}
|
||||
align="start"
|
||||
side="bottom"
|
||||
data-toc-popover=""
|
||||
{...props}
|
||||
className={cn(
|
||||
'flex max-h-[var(--radix-popover-content-available-height)] w-[260px] flex-col gap-4 p-3',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</PopoverContent>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +1,21 @@
|
||||
'use client';
|
||||
import type { TOCItemType } from 'fumadocs-core/server';
|
||||
import * as Primitive from 'fumadocs-core/toc';
|
||||
import { type HTMLAttributes, type ReactNode, useRef } from 'react';
|
||||
import { type HTMLAttributes, type ReactNode, useMemo, useRef } from 'react';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { useI18n } from '@/contexts/i18n';
|
||||
import { TocThumb } from '@/components/layout/toc-thumb';
|
||||
import { ScrollArea, ScrollViewport } from '../ui/scroll-area';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import type {
|
||||
PopoverContentProps,
|
||||
PopoverTriggerProps,
|
||||
} from '@radix-ui/react-popover';
|
||||
import { ChevronRight, Text } from 'lucide-react';
|
||||
|
||||
export interface TOCProps {
|
||||
/**
|
||||
@@ -105,3 +115,54 @@ function TOCItem({ item }: { item: TOCItemType }) {
|
||||
</Primitive.TOCItem>
|
||||
);
|
||||
}
|
||||
|
||||
export const TocPopover = Popover;
|
||||
|
||||
export function TocPopoverTrigger({
|
||||
items,
|
||||
...props
|
||||
}: PopoverTriggerProps & { items: TOCItemType[] }) {
|
||||
const { text } = useI18n();
|
||||
const active = Primitive.useActiveAnchor();
|
||||
const current = useMemo(() => {
|
||||
return items.find((item) => active === item.url.slice(1))?.title;
|
||||
}, [items, active]);
|
||||
|
||||
return (
|
||||
<PopoverTrigger
|
||||
{...props}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-2 text-nowrap px-4 py-2 text-start',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
<Text className="size-4 shrink-0" />
|
||||
{text.toc}
|
||||
{current ? (
|
||||
<>
|
||||
<ChevronRight className="-mx-1.5 size-4 shrink-0 text-fd-muted-foreground" />
|
||||
<span className="truncate text-fd-muted-foreground">{current}</span>
|
||||
</>
|
||||
) : null}
|
||||
</PopoverTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
export function TocPopoverContent(props: PopoverContentProps) {
|
||||
return (
|
||||
<PopoverContent
|
||||
hideWhenDetached
|
||||
alignOffset={16}
|
||||
align="start"
|
||||
side="bottom"
|
||||
data-toc-popover=""
|
||||
{...props}
|
||||
className={cn(
|
||||
'flex max-h-[var(--radix-popover-content-available-height)] w-[260px] flex-col gap-4 p-3',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</PopoverContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,27 @@ import {
|
||||
} from '@/components/ui/collapsible';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import { buttonVariants } from '@/components/ui/button';
|
||||
import { useSidebar } from '@/contexts/sidebar';
|
||||
|
||||
export function LayoutBody(props: HTMLAttributes<HTMLElement>) {
|
||||
const { collapsed } = useSidebar();
|
||||
|
||||
return (
|
||||
<main
|
||||
{...props}
|
||||
style={
|
||||
{
|
||||
'--fd-page-width': collapsed
|
||||
? '100vw'
|
||||
: 'calc(min(100vw, var(--fd-layout-width)) - var(--fd-sidebar-width) - var(--fd-toc-width))',
|
||||
...props.style,
|
||||
} as object
|
||||
}
|
||||
>
|
||||
{props.children}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
const itemVariants = cva(
|
||||
'flex flex-row items-center gap-2 rounded-md px-3 py-2.5 text-fd-muted-foreground transition-colors duration-100 [overflow-wrap:anywhere] hover:bg-fd-accent/50 hover:text-fd-accent-foreground/80 hover:transition-none md:px-2 md:py-1.5 [&_svg]:size-4',
|
||||
@@ -68,11 +89,11 @@ export function MenuItem({ item, ...props }: MenuItemProps) {
|
||||
<Collapsible className="flex flex-col">
|
||||
<CollapsibleTrigger
|
||||
{...props}
|
||||
className={cn(itemVariants(), 'group/link', props.className)}
|
||||
className={cn(itemVariants(), 'group', props.className)}
|
||||
>
|
||||
{item.icon}
|
||||
{item.text}
|
||||
<ChevronDown className="ms-auto transition-transform group-data-[state=closed]/link:-rotate-90" />
|
||||
<ChevronDown className="ms-auto transition-transform group-data-[state=closed]:-rotate-90" />
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<div className="flex flex-col py-2 ps-2">
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
LanguageToggle,
|
||||
LanguageToggleText,
|
||||
} from '@/components/layout/language-toggle';
|
||||
import { LinksMenu } from '@/layouts/docs.client';
|
||||
import { LayoutBody, LinksMenu } from '@/layouts/docs.client';
|
||||
import { TreeContextProvider } from '@/contexts/tree';
|
||||
import { NavProvider, Title } from '@/components/layout/nav';
|
||||
import { ThemeToggle } from '@/components/layout/theme-toggle';
|
||||
@@ -94,7 +94,7 @@ export function DocsLayout({
|
||||
</Navbar>,
|
||||
nav,
|
||||
)}
|
||||
<main
|
||||
<LayoutBody
|
||||
id="nd-docs-layout"
|
||||
{...props.containerProps}
|
||||
className={cn(
|
||||
@@ -110,7 +110,10 @@ export function DocsLayout({
|
||||
) : null}
|
||||
{replaceOrDefault(
|
||||
{ enabled: sidebarEnabled, component: sidebarReplace },
|
||||
<Aside {...sidebar}>
|
||||
<Aside
|
||||
{...sidebar}
|
||||
className="md:flex-1 md:data-[collapsed=true]:flex-initial"
|
||||
>
|
||||
<SidebarHeader>
|
||||
<SidebarHeaderItems {...nav} links={links} />
|
||||
{sidebarBanner}
|
||||
@@ -149,7 +152,7 @@ export function DocsLayout({
|
||||
},
|
||||
)}
|
||||
{props.children}
|
||||
</main>
|
||||
</LayoutBody>
|
||||
</NavProvider>
|
||||
</TreeContextProvider>
|
||||
);
|
||||
|
||||
@@ -15,8 +15,8 @@ export function Navbar(props: HTMLAttributes<HTMLElement>) {
|
||||
<header
|
||||
{...props}
|
||||
className={cn(
|
||||
'sticky top-[var(--fd-banner-height)] z-30 flex flex-row items-center border-b border-fd-foreground/10 px-4 transition-colors',
|
||||
(!isTransparent || open) && 'bg-fd-background/80 backdrop-blur-lg',
|
||||
'sticky top-[var(--fd-banner-height)] z-30 flex flex-row items-center border-b border-fd-foreground/10 px-4 backdrop-blur-lg transition-colors',
|
||||
(!isTransparent || open) && 'bg-fd-background/80',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -119,9 +119,9 @@ export function CollapsibleSidebar(props: SidebarProps) {
|
||||
onPointerLeave={onLeave}
|
||||
data-collapsed={collapsed}
|
||||
className={cn(
|
||||
'transition-[flex,margin,opacity,transform]',
|
||||
'md:transition-all',
|
||||
collapsed &&
|
||||
'md:-me-[var(--fd-sidebar-width)] md:flex-initial md:translate-x-[calc(var(--fd-sidebar-offset)*-1)] rtl:md:translate-x-[var(--fd-sidebar-offset)]',
|
||||
'md:-me-[var(--fd-sidebar-width)] md:translate-x-[calc(var(--fd-sidebar-offset)*-1)] rtl:md:translate-x-[var(--fd-sidebar-offset)]',
|
||||
collapsed && hover && 'z-50 md:translate-x-0',
|
||||
collapsed && !hover && 'md:opacity-0',
|
||||
props.className,
|
||||
@@ -155,7 +155,7 @@ export function Sidebar({
|
||||
blockScrollingWidth={768} // md
|
||||
{...props}
|
||||
className={cn(
|
||||
'fixed top-fd-layout-top z-30 bg-fd-card text-sm md:sticky md:h-[var(--fd-sidebar-height)] md:flex-1',
|
||||
'fixed top-fd-layout-top z-30 bg-fd-card text-sm md:sticky md:h-[var(--fd-sidebar-height)]',
|
||||
'max-md:inset-x-0 max-md:bottom-0 max-md:bg-fd-background/80 max-md:text-[15px] max-md:backdrop-blur-lg max-md:data-[open=false]:invisible',
|
||||
props.className,
|
||||
)}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
'use client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
import type { ButtonHTMLAttributes, HTMLAttributes } from 'react';
|
||||
import { useSidebar } from '@/contexts/sidebar';
|
||||
import { useNav } from '@/components/layout/nav';
|
||||
import { SidebarTrigger } from 'fumadocs-core/sidebar';
|
||||
import { buttonVariants } from '@/components/ui/button';
|
||||
import { Menu, X } from 'lucide-react';
|
||||
|
||||
export function LayoutBody(props: HTMLAttributes<HTMLElement>) {
|
||||
const { collapsed } = useSidebar();
|
||||
|
||||
return (
|
||||
<main
|
||||
id="nd-docs-layout"
|
||||
@@ -14,9 +16,9 @@ export function LayoutBody(props: HTMLAttributes<HTMLElement>) {
|
||||
style={
|
||||
{
|
||||
...props.style,
|
||||
'--fd-content-width': collapsed
|
||||
? '100vw'
|
||||
: 'calc(min(100vw, var(--fd-layout-width)) - var(--fd-sidebar-width))',
|
||||
'--fd-layout-offset':
|
||||
'max(calc(50vw - var(--fd-layout-width) / 2), 0px)',
|
||||
paddingInlineEnd: 'var(--fd-layout-offset)',
|
||||
} as object
|
||||
}
|
||||
>
|
||||
@@ -24,3 +26,53 @@ export function LayoutBody(props: HTMLAttributes<HTMLElement>) {
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export function SubNavbar(props: HTMLAttributes<HTMLElement>) {
|
||||
const { open, collapsed } = useSidebar();
|
||||
const { isTransparent } = useNav();
|
||||
|
||||
return (
|
||||
<header
|
||||
id="nd-subnav"
|
||||
{...props}
|
||||
className={cn(
|
||||
'fixed inset-x-0 top-[var(--fd-banner-height)] z-10 h-14 backdrop-blur-lg transition-colors',
|
||||
(!isTransparent || open) && 'bg-fd-background/80',
|
||||
props.className,
|
||||
)}
|
||||
style={
|
||||
{
|
||||
paddingInlineStart: collapsed
|
||||
? 'calc(var(--fd-layout-offset))'
|
||||
: 'calc(var(--fd-layout-offset) + var(--fd-sidebar-width))',
|
||||
paddingInlineEnd: 'var(--fd-layout-offset)',
|
||||
} as object
|
||||
}
|
||||
>
|
||||
<div className="mx-auto flex size-full flex-row items-center border-b border-fd-foreground/10 px-4 md:gap-1.5 lg:px-8">
|
||||
{props.children}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
export function NavbarSidebarTrigger(
|
||||
props: ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
) {
|
||||
const { open } = useSidebar();
|
||||
|
||||
return (
|
||||
<SidebarTrigger
|
||||
{...props}
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
color: 'ghost',
|
||||
size: 'icon',
|
||||
}),
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
{open ? <X /> : <Menu />}
|
||||
</SidebarTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import { notFound } from 'next/navigation';
|
||||
import { RootToggle } from '@/components/layout/root-toggle';
|
||||
import { TreeContextProvider } from '@/contexts/tree';
|
||||
import { NavProvider, Title } from '@/components/layout/nav';
|
||||
import { Navbar, NavbarSidebarTrigger } from '@/layouts/docs/navbar';
|
||||
import { SearchOnly } from '@/contexts/search';
|
||||
import {
|
||||
LargeSearchToggle,
|
||||
@@ -41,7 +40,7 @@ import {
|
||||
type SidebarOptions,
|
||||
} from '@/layouts/docs/shared';
|
||||
import type { PageTree } from 'fumadocs-core/server';
|
||||
import { LayoutBody } from './notebook.client';
|
||||
import { LayoutBody, SubNavbar, NavbarSidebarTrigger } from './notebook.client';
|
||||
|
||||
export interface DocsLayoutProps extends BaseLayoutProps {
|
||||
tree: PageTree.Root;
|
||||
@@ -76,13 +75,16 @@ export function DocsLayout({
|
||||
<LayoutBody
|
||||
{...props.containerProps}
|
||||
className={cn(
|
||||
'[--fd-nav-height:3.5rem] md:[--fd-sidebar-width:260px] lg:[--fd-toc-width:260px] [&_#nd-toc]:max-lg:hidden [&_#nd-tocnav]:lg:hidden',
|
||||
'[--fd-nav-height:3.5rem] md:[--fd-sidebar-width:260px] lg:[--fd-toc-width:260px] [&_#nd-page]:mt-[var(--fd-nav-height)] [&_#nd-toc]:max-lg:hidden [&_#nd-tocnav]:lg:hidden',
|
||||
props.containerProps?.className,
|
||||
)}
|
||||
>
|
||||
<Aside
|
||||
{...sidebar}
|
||||
className={cn('md:[--fd-nav-height:0px]', sidebar.className)}
|
||||
className={cn(
|
||||
'md:ps-[var(--fd-layout-offset)] md:[--fd-nav-height:0px]',
|
||||
sidebar.className,
|
||||
)}
|
||||
>
|
||||
<SidebarHeader>
|
||||
<SidebarHeaderItems nav={nav} links={links}>
|
||||
@@ -108,21 +110,13 @@ export function DocsLayout({
|
||||
</SidebarViewport>
|
||||
<SidebarFooter>{sidebarFooter}</SidebarFooter>
|
||||
</Aside>
|
||||
<div className="w-full min-w-0 max-w-[var(--fd-content-width)] [--fd-nav-height:3.5rem]">
|
||||
<DocsNavbar
|
||||
nav={nav}
|
||||
links={links}
|
||||
i18n={i18n}
|
||||
sidebarCollapsible={sidebarCollapsible}
|
||||
/>
|
||||
<div className="flex flex-row">{props.children}</div>
|
||||
</div>
|
||||
<div
|
||||
className="min-w-[var(--fd-sidebar-width)] flex-1"
|
||||
style={{
|
||||
marginInlineStart: 'calc(var(--fd-sidebar-width) * -1)',
|
||||
}}
|
||||
<DocsNavbar
|
||||
nav={nav}
|
||||
links={links}
|
||||
i18n={i18n}
|
||||
sidebarCollapsible={sidebarCollapsible}
|
||||
/>
|
||||
{props.children}
|
||||
</LayoutBody>
|
||||
</NavProvider>
|
||||
</TreeContextProvider>
|
||||
@@ -141,7 +135,7 @@ function DocsNavbar({
|
||||
links: LinkItemType[];
|
||||
}) {
|
||||
return (
|
||||
<Navbar id="nd-subnav" className="h-14 md:gap-1.5">
|
||||
<SubNavbar>
|
||||
{sidebarCollapsible ? (
|
||||
<SidebarCollapseTrigger className="-ms-1.5 text-fd-muted-foreground data-[collapsed=false]:hidden max-md:hidden" />
|
||||
) : null}
|
||||
@@ -188,7 +182,7 @@ function DocsNavbar({
|
||||
</LanguageToggle>
|
||||
) : null}
|
||||
<ThemeToggle className="p-0 max-md:hidden" />
|
||||
</Navbar>
|
||||
</SubNavbar>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,30 +22,6 @@ import {
|
||||
getBreadcrumbItemsFromPath,
|
||||
} from 'fumadocs-core/breadcrumb';
|
||||
|
||||
export function PageContainer(props: HTMLAttributes<HTMLDivElement>) {
|
||||
const { collapsed } = useSidebar();
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn(
|
||||
'flex w-full min-w-0 max-w-[var(--fd-page-width)] flex-col md:transition-[max-width]',
|
||||
props.className,
|
||||
)}
|
||||
style={
|
||||
{
|
||||
...props.style,
|
||||
'--fd-page-width': collapsed
|
||||
? '100vw'
|
||||
: 'calc(min(100vw, var(--fd-layout-width)) - var(--fd-sidebar-width) - var(--fd-toc-width))',
|
||||
} as object
|
||||
}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function PageHeader(props: HTMLAttributes<HTMLDivElement>) {
|
||||
const { open } = useSidebar();
|
||||
const { isTransparent } = useNav();
|
||||
@@ -54,8 +30,8 @@ export function PageHeader(props: HTMLAttributes<HTMLDivElement>) {
|
||||
<header
|
||||
{...props}
|
||||
className={cn(
|
||||
'sticky top-fd-layout-top z-10 flex flex-row items-center border-b border-fd-foreground/10 text-sm transition-colors',
|
||||
!isTransparent && 'bg-fd-background/80 backdrop-blur-md',
|
||||
'sticky top-fd-layout-top z-10 flex flex-row items-center border-b border-fd-foreground/10 text-sm backdrop-blur-md transition-colors',
|
||||
!isTransparent && 'bg-fd-background/80',
|
||||
open && 'opacity-0',
|
||||
props.className,
|
||||
)}
|
||||
|
||||
+26
-12
@@ -14,17 +14,18 @@ import {
|
||||
Footer,
|
||||
type FooterProps,
|
||||
LastUpdate,
|
||||
PageContainer,
|
||||
PageHeader,
|
||||
Breadcrumb,
|
||||
type BreadcrumbProps,
|
||||
} from './page.client';
|
||||
import { Toc, TOCItems, type TOCProps } from '@/components/layout/toc';
|
||||
import {
|
||||
Toc,
|
||||
TOCItems,
|
||||
TocPopoverTrigger,
|
||||
TocPopover,
|
||||
TocPopoverContent,
|
||||
} from '@/components/layout/toc-popover';
|
||||
type TOCProps,
|
||||
} from '@/components/layout/toc';
|
||||
import { buttonVariants } from '@/components/ui/button';
|
||||
import { Edit, Text } from 'lucide-react';
|
||||
import { I18nLabel } from '@/contexts/i18n';
|
||||
@@ -105,14 +106,14 @@ export interface DocsPageProps {
|
||||
editOnGithub?: EditOnGitHubOptions;
|
||||
lastUpdate?: Date | string | number;
|
||||
|
||||
container?: HTMLAttributes<HTMLDivElement>;
|
||||
article?: HTMLAttributes<HTMLElement>;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function DocsPage({
|
||||
toc = [],
|
||||
breadcrumb = {},
|
||||
full = false,
|
||||
footer = {},
|
||||
tableOfContentPopover: {
|
||||
enabled: tocPopoverEnabled = true,
|
||||
component: tocPopoverReplace,
|
||||
@@ -135,8 +136,13 @@ export function DocsPage({
|
||||
|
||||
return (
|
||||
<AnchorProvider toc={toc} single={tocOptions.single}>
|
||||
<PageContainer
|
||||
<div
|
||||
id="nd-page"
|
||||
{...props.container}
|
||||
className={cn(
|
||||
'flex w-full min-w-0 max-w-[var(--fd-page-width)] flex-col md:transition-[max-width]',
|
||||
props.container?.className,
|
||||
)}
|
||||
style={
|
||||
{
|
||||
'--fd-toc-width': fullWidth ? '0px' : undefined,
|
||||
@@ -165,14 +171,19 @@ export function DocsPage({
|
||||
},
|
||||
)}
|
||||
<article
|
||||
{...props.article}
|
||||
className={cn(
|
||||
'mx-auto flex w-full flex-1 flex-col gap-6 px-4 pt-10 md:px-7 md:pt-12',
|
||||
'mx-auto flex w-full flex-1 flex-col gap-6 px-4 pt-8 md:pt-12 lg:px-8',
|
||||
fullWidth ? 'max-w-[1120px]' : 'max-w-[860px]',
|
||||
props.article?.className,
|
||||
)}
|
||||
>
|
||||
{replaceOrDefault(
|
||||
breadcrumb,
|
||||
<Breadcrumb includePage={breadcrumb.full} {...breadcrumb} />,
|
||||
props.breadcrumb,
|
||||
<Breadcrumb
|
||||
includePage={props.breadcrumb?.full}
|
||||
{...props.breadcrumb}
|
||||
/>,
|
||||
)}
|
||||
{props.children}
|
||||
<div role="none" className="flex-1" />
|
||||
@@ -184,9 +195,12 @@ export function DocsPage({
|
||||
<LastUpdate date={new Date(props.lastUpdate)} />
|
||||
) : null}
|
||||
</div>
|
||||
{replaceOrDefault(footer, <Footer items={footer.items} />)}
|
||||
{replaceOrDefault(
|
||||
props.footer,
|
||||
<Footer items={props.footer?.items} />,
|
||||
)}
|
||||
</article>
|
||||
</PageContainer>
|
||||
</div>
|
||||
{replaceOrDefault(
|
||||
{ enabled: tocEnabled, component: tocReplace },
|
||||
<Toc id="nd-toc">
|
||||
@@ -232,7 +246,7 @@ function EditOnGitHub({
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
color: 'secondary',
|
||||
className: 'gap-1.5 py-1 text-fd-muted-foreground',
|
||||
className: 'gap-1.5 text-fd-muted-foreground',
|
||||
}),
|
||||
props.className,
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user