Files
myeasycms-v2/apps/web/app/[locale]/docs/_components/docs-navigation.tsx
Giancarlo Buomprisco 7ebff31475 Next.js Supabase V3 (#463)
Version 3 of the kit:
- Radix UI replaced with Base UI (using the Shadcn UI patterns)
- next-intl replaces react-i18next
- enhanceAction deprecated; usage moved to next-safe-action
- main layout now wrapped with [locale] path segment
- Teams only mode
- Layout updates
- Zod v4
- Next.js 16.2
- Typescript 6
- All other dependencies updated
- Removed deprecated Edge CSRF
- Dynamic Github Action runner
2026-03-24 13:40:38 +08:00

150 lines
3.0 KiB
TypeScript

import { ChevronDown } from 'lucide-react';
import { Cms } from '@kit/cms';
import { CollapsibleContent, CollapsibleTrigger } from '@kit/ui/collapsible';
import {
Sidebar,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
} from '@kit/ui/sidebar';
import { DocsNavLink } from '../_components/docs-nav-link';
import { DocsNavigationCollapsible } from '../_components/docs-navigation-collapsible';
import { FloatingDocumentationNavigationButton } from './floating-docs-navigation-button';
function Node({
node,
level,
prefix,
}: {
node: Cms.ContentItem;
level: number;
prefix: string;
}) {
const url = `${prefix}/${node.slug}`;
const label = node.label ? node.label : node.title;
return (
<NodeContainer node={node} prefix={prefix}>
<NodeTrigger node={node} label={label} url={url} />
<NodeContentContainer node={node}>
<Tree pages={node.children ?? []} level={level + 1} prefix={prefix} />
</NodeContentContainer>
</NodeContainer>
);
}
function NodeContentContainer({
node,
children,
}: {
node: Cms.ContentItem;
children: React.ReactNode;
}) {
if (node.collapsible) {
return <CollapsibleContent>{children}</CollapsibleContent>;
}
return children;
}
function NodeContainer({
node,
prefix,
children,
}: {
node: Cms.ContentItem;
prefix: string;
children: React.ReactNode;
}) {
if (node.collapsible) {
return (
<DocsNavigationCollapsible node={node} prefix={prefix}>
{children}
</DocsNavigationCollapsible>
);
}
return children;
}
function NodeTrigger({
node,
label,
url,
}: {
node: Cms.ContentItem;
label: string;
url: string;
}) {
if (node.collapsible) {
return (
<CollapsibleTrigger render={<SidebarMenuItem />}>
<SidebarMenuButton>
{label}
<ChevronDown className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" />
</SidebarMenuButton>
</CollapsibleTrigger>
);
}
return <DocsNavLink label={label} url={url} />;
}
function Tree({
pages,
level,
prefix,
}: {
pages: Cms.ContentItem[];
level: number;
prefix: string;
}) {
if (level === 0) {
return pages.map((treeNode, index) => (
<Node key={index} node={treeNode} level={level} prefix={prefix} />
));
}
if (pages.length === 0) {
return null;
}
return (
<SidebarMenuSub>
{pages.map((treeNode, index) => (
<Node key={index} node={treeNode} level={level} prefix={prefix} />
))}
</SidebarMenuSub>
);
}
export function DocsNavigation({
pages,
prefix = '/docs',
}: {
pages: Cms.ContentItem[];
prefix?: string;
}) {
return (
<>
<Sidebar variant={'floating'}>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu className={'pb-48'}>
<Tree pages={pages} level={0} prefix={prefix} />
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</Sidebar>
<FloatingDocumentationNavigationButton />
</>
);
}