UI: Improve theme toggle on Notebook layout

This commit is contained in:
Fuma Nama
2024-12-23 16:06:11 +08:00
parent 6d9c81f7f6
commit 67124b15bc
6 changed files with 78 additions and 71 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-ui': patch
---
Improve theme toggle on Notebook layout
+1 -1
View File
@@ -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 { baseOptions, linkItems } from '@/app/layout.config';
+2 -2
View File
@@ -19,7 +19,6 @@ import {
type IconItemType,
BaseLinkItem,
} from '@/layouts/links';
import { getSidebarTabs, type TabOptions } from '@/utils/get-sidebar-tabs';
import { RootToggle } from '@/components/layout/root-toggle';
import { type BaseLayoutProps, getLinks } from './shared';
import {
@@ -268,4 +267,5 @@ function SidebarFooterItems({
);
}
export { getSidebarTabs, type TabOptions, type LinkItemType };
export { getSidebarTabsFromOptions, type TabOptions } from './docs/shared';
export { type LinkItemType };
+64 -1
View File
@@ -10,7 +10,6 @@ import {
import { cn } from '@/utils/cn';
import { buttonVariants } from '@/components/ui/button';
import type { PageTree } from 'fumadocs-core/server';
import { getSidebarTabs, type TabOptions } from '@/utils/get-sidebar-tabs';
import type { FC, ReactNode } from 'react';
import type { Option } from '@/components/layout/root-toggle';
@@ -18,6 +17,10 @@ export const layoutVariables = {
'--fd-layout-offset': 'max(calc(50vw - var(--fd-layout-width) / 2), 0px)',
};
export interface TabOptions {
transform?: (option: Option, node: PageTree.Folder) => Option | null;
}
export interface SidebarOptions extends SidebarProps {
enabled: boolean;
component: ReactNode;
@@ -108,3 +111,63 @@ export function getSidebarTabsFromOptions(
return getSidebarTabs(tree);
}
}
const defaultTransform: TabOptions['transform'] = (option, node) => {
if (!node.icon) return option;
return {
...option,
icon: (
<div className="rounded-md border bg-fd-secondary p-1 shadow-md [&_svg]:size-5">
{node.icon}
</div>
),
};
};
function getSidebarTabs(
pageTree: PageTree.Root,
{ transform = defaultTransform }: TabOptions = {},
): Option[] {
function findOptions(node: PageTree.Folder): Option[] {
const results: Option[] = [];
if (node.root) {
const index = node.index ?? node.children.at(0);
if (index?.type === 'page') {
const option: Option = {
url: index.url,
title: node.name,
icon: node.icon,
description: node.description,
urls: getFolderUrls(node),
};
const mapped = transform ? transform(option, node) : option;
if (mapped) results.push(mapped);
}
}
for (const child of node.children) {
if (child.type === 'folder') results.push(...findOptions(child));
}
return results;
}
return findOptions(pageTree as PageTree.Folder);
}
function getFolderUrls(folder: PageTree.Folder): string[] {
const results: string[] = [];
if (folder.index) results.push(folder.index.url);
for (const child of folder.children) {
if (child.type === 'page') results.push(child.url);
if (child.type === 'folder') results.push(...getFolderUrls(child));
}
return results;
}
+6 -1
View File
@@ -125,7 +125,12 @@ export function DocsLayout({
<SidebarPageTree components={sidebarComponents} />
</div>
</SidebarViewport>
<SidebarFooter>{sidebarFooter}</SidebarFooter>
<SidebarFooter className={cn(!sidebarFooter && 'md:hidden')}>
{!props.disableThemeSwitch ? (
<ThemeToggle className="w-fit md:hidden" />
) : null}
{sidebarFooter}
</SidebarFooter>
</Aside>
<DocsNavbar
nav={nav}
@@ -1,66 +0,0 @@
import type { PageTree } from 'fumadocs-core/server';
import type { Option } from '@/components/layout/root-toggle';
export interface TabOptions {
transform?: (option: Option, node: PageTree.Folder) => Option | null;
}
const defaultTransform: TabOptions['transform'] = (option, node) => {
if (!node.icon) return option;
return {
...option,
icon: (
<div className="rounded-md border bg-fd-secondary p-1 shadow-md [&_svg]:size-5">
{node.icon}
</div>
),
};
};
export function getSidebarTabs(
pageTree: PageTree.Root,
{ transform = defaultTransform }: TabOptions = {},
): Option[] {
function findOptions(node: PageTree.Folder): Option[] {
const results: Option[] = [];
if (node.root) {
const index = node.index ?? node.children.at(0);
if (index?.type === 'page') {
const option: Option = {
url: index.url,
title: node.name,
icon: node.icon,
description: node.description,
urls: getFolderUrls(node),
};
const mapped = transform ? transform(option, node) : option;
if (mapped) results.push(mapped);
}
}
for (const child of node.children) {
if (child.type === 'folder') results.push(...findOptions(child));
}
return results;
}
return findOptions(pageTree as PageTree.Folder);
}
function getFolderUrls(folder: PageTree.Folder): string[] {
const results: string[] = [];
if (folder.index) results.push(folder.index.url);
for (const child of folder.children) {
if (child.type === 'page') results.push(child.url);
if (child.type === 'folder') results.push(...getFolderUrls(child));
}
return results;
}