Skip to content

Commit e27c1c0

Browse files
refactor: update sidebar and UI components
- Migrated getPageTreePeers import from 'fumadocs-core/server' to 'fumadocs-core/page-tree' across doc pages - Simplified Sidebar component by removing ScrollArea and internal context management - Added sidebar-specific CSS variables and dark mode support in global.css - Added new button variants and sizes in button component - Added new Sheet component with Radix UI Dialog primitives - Improved folder navigation handling in sidebar with useEffect hook
1 parent 892bfef commit e27c1c0

File tree

21 files changed

+1130
-138
lines changed

21 files changed

+1130
-138
lines changed

app/docs/changelog/[...slug]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { PageTOC } from 'fumadocs-ui/layouts/docs/page'
77

88
import { TOCScrollArea } from 'fumadocs-ui/components/layout/toc';
99
import ClerkTOCItems from 'fumadocs-ui/components/layout/toc-clerk';
10-
import { getPageTreePeers } from 'fumadocs-core/server';
10+
import { getPageTreePeers } from 'fumadocs-core/page-tree';
1111
import { Cards, Card } from 'fumadocs-ui/components/card';
1212
import TOCMobile from '@/components/layout/TOCMobile';
1313
import { TOCProvider } from 'fumadocs-ui/components/layout/toc';

app/docs/legal/[[...slug]]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { AnchorProvider } from 'fumadocs-core/toc';
77
import { TOCProvider, TOCScrollArea } from 'fumadocs-ui/components/layout/toc';
88
import { PageTOC } from 'fumadocs-ui/layouts/docs/page'
99
import ClerkTOCItems from 'fumadocs-ui/components/layout/toc-clerk';
10-
import { getPageTreePeers } from 'fumadocs-core/server';
10+
import { getPageTreePeers } from 'fumadocs-core/page-tree';
1111
import { Cards, Card } from 'fumadocs-ui/components/card';
1212
import TOCMobile from '@/components/layout/TOCMobile';
1313

app/docs/product-docs/[[...slug]]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { AnchorProvider } from 'fumadocs-core/toc';
77
import { TOCProvider, TOCScrollArea } from 'fumadocs-ui/components/layout/toc';
88
import { PageTOC } from 'fumadocs-ui/layouts/docs/page'
99
import ClerkTOCItems from 'fumadocs-ui/components/layout/toc-clerk';
10-
import { getPageTreePeers } from 'fumadocs-core/server';
10+
import { getPageTreePeers } from 'fumadocs-core/page-tree';
1111
import { Cards, Card } from 'fumadocs-ui/components/card';
1212
import TOCMobile from '@/components/layout/TOCMobile';
1313

app/docs/scripts/[[...slug]]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { PageTOC } from 'fumadocs-ui/layouts/docs/page'
77
import { TOCProvider, TOCScrollArea } from 'fumadocs-ui/components/layout/toc';
88
import ClerkTOCItems from 'fumadocs-ui/components/layout/toc-clerk';
99
import TOCMobile from '@/components/layout/TOCMobile';
10-
import { getPageTreePeers } from 'fumadocs-core/server';
10+
import { getPageTreePeers } from 'fumadocs-core/page-tree';
1111
import { Cards, Card } from 'fumadocs-ui/components/card';
1212

1313
export default async function Page(props: {

app/docs/self-hosting/[[...slug]]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { AnchorProvider } from 'fumadocs-core/toc';
77
import { TOCProvider, TOCScrollArea } from 'fumadocs-ui/components/layout/toc';
88
import { PageTOC } from 'fumadocs-ui/layouts/docs/page'
99
import ClerkTOCItems from 'fumadocs-ui/components/layout/toc-clerk';
10-
import { getPageTreePeers } from 'fumadocs-core/server';
10+
import { getPageTreePeers } from 'fumadocs-core/page-tree';
1111
import { Cards, Card } from 'fumadocs-ui/components/card';
1212
import TOCMobile from '@/components/layout/TOCMobile';
1313

app/global.css

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@
126126

127127
--color-base-none: #ffffff00;
128128
--radius: 0.5rem;
129+
--sidebar: hsl(0 0% 98%);
130+
--sidebar-foreground: hsl(240 5.3% 26.1%);
131+
--sidebar-primary: hsl(240 5.9% 10%);
132+
--sidebar-primary-foreground: hsl(0 0% 98%);
133+
--sidebar-accent: hsl(240 4.8% 95.9%);
134+
--sidebar-accent-foreground: hsl(240 5.9% 10%);
135+
--sidebar-border: hsl(220 13% 91%);
136+
--sidebar-ring: hsl(217.2 91.2% 59.8%);
129137
}
130138

131139
.dark {
@@ -241,6 +249,14 @@
241249
--color-yellow-700: #ffe3a6;
242250
--color-yellow-800: #ffefcc;
243251
--color-yellow-900: #fff7e5;
252+
--sidebar: hsl(240 5.9% 10%);
253+
--sidebar-foreground: hsl(240 4.8% 95.9%);
254+
--sidebar-primary: hsl(224.3 76.3% 48%);
255+
--sidebar-primary-foreground: hsl(0 0% 100%);
256+
--sidebar-accent: hsl(240 3.7% 15.9%);
257+
--sidebar-accent-foreground: hsl(240 4.8% 95.9%);
258+
--sidebar-border: hsl(240 3.7% 15.9%);
259+
--sidebar-ring: hsl(217.2 91.2% 59.8%);
244260
}
245261

246262
@theme inline {
@@ -260,7 +276,6 @@
260276
--font-size-h2: 40px;
261277
--font-size-h3: 24px;
262278

263-
264279
--measurements-radius-x-small: var(--spacing-02);
265280
--measurements-radius-small: var(--spacing-03);
266281
--measurements-radius-medium: var(--spacing-04);
@@ -294,14 +309,21 @@
294309
--font-weight-bold: 700;
295310
--font-weight-black: 800;
296311

297-
298312
--shadow-default: 0px 0px 4px 0px rgba(0, 0, 0, 0.08);
299313
--shadow-hover: 0px 0px 4px 0px rgba(0, 0, 0, 0.24);
300314
--shadow-selected: 0px 0px 0px 2px var(--color-ant-primary-color-outline);
301315
--shadow-selected-ai: 0px 0px 0px 2px rgba(125, 38, 205, 0.24);
302316
--shadow-error: 0px 0px 0px 2px var(--color-ant-error-color-outline);
303317
--shadow-focus: 0px 0px 0px 2px #fff, 0px 0px 0px 4px #3069fe;
304318
--shadow-nc-sm: 0px 3px 1px -2px rgba(0, 0, 0, 0.06), 0px 5px 3px -2px rgba(0, 0, 0, 0.02);
319+
--color-sidebar-ring: var(--sidebar-ring);
320+
--color-sidebar-border: var(--sidebar-border);
321+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
322+
--color-sidebar-accent: var(--sidebar-accent);
323+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
324+
--color-sidebar-primary: var(--sidebar-primary);
325+
--color-sidebar-foreground: var(--sidebar-foreground);
326+
--color-sidebar: var(--sidebar);
305327

306328
}
307329

@@ -464,7 +486,6 @@
464486
--radius-lg: var(--radius);
465487
--radius-xl: calc(var(--radius) + 4px);
466488

467-
468489
--shadow-sm: 0px 3px 1px -2px rgba(0, 0, 0, 0.06), 0px 5px 3px -2px rgba(0, 0, 0, 0.02);
469490
--shadow-default: 0px 0px 4px 0px rgba(0, 0, 0, 0.08);
470491
--shadow-hover: 0px 0px 4px 0px rgba(0, 0, 0, 0.24);
@@ -492,7 +513,6 @@
492513
--color-border: var(--color-nc-border-grey-medium);
493514
--color-input: var(--color-nc-content-grey-subtle);
494515

495-
496516
--color-ant-primary-hover: #6e7ef5;
497517
--color-ant-primary-active: #2f36c2;
498518
--color-ant-primary-outline: #4351e833;
@@ -509,7 +529,6 @@
509529
--color-fd-primary: var(--color-nc-content-grey-emphasis);
510530
--color-fd-accent: var(--color-nc-background-grey-medium);
511531

512-
513532
--color-fd-background: var(--color-grey-50);
514533
--color-fd-foreground: var(--color-grey-900);
515534
--color-fd-muted: var(--color-grey-100);
@@ -575,7 +594,6 @@
575594
}
576595
}
577596

578-
579597
[id="nd-home-layout"] {
580598
padding-top: 18px !important;
581599
}
@@ -584,12 +602,10 @@
584602
inset-inline-end: 0 !important;
585603
}
586604

587-
588605
.grecaptcha-badge {
589606
@apply hidden;
590607
}
591608

592-
593609
.nc-docs-layout {
594610
[role="tablist"] {
595611
button:is([role="tab"]):is([aria-selected="true"]) {
@@ -665,4 +681,15 @@
665681
}
666682
}
667683
}
684+
}
685+
686+
/*---break---*/
687+
688+
@layer base {
689+
* {
690+
@apply border-border;
691+
}
692+
body {
693+
@apply bg-background text-foreground;
694+
}
668695
}

components/blog/CustomToc.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22
import {useRef} from "react";
33
import * as Base from 'fumadocs-core/toc';
4-
import {TableOfContents} from "fumadocs-core/server";
4+
import {TableOfContents} from "fumadocs-core/toc";
55

66
export default function CustomToc({toc}: { toc: TableOfContents }) {
77
const containerRef = useRef<HTMLDivElement>(null);

components/layout/Sidebar.tsx

Lines changed: 29 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
"use client";
2-
import * as SidebarPrimitive from "fumadocs-core/sidebar";
3-
import {useSidebar, useTreeContext, useTreePath} from "fumadocs-ui/provider";
4-
import {createContext, ReactNode, useContext, useMemo, useState, useCallback} from "react";
2+
import {useTreeContext, useTreePath} from "fumadocs-ui/provider";
3+
import {createContext, ReactNode, useContext, useMemo, useState, useCallback, useEffect} from "react";
54
import {useDocsNavigation} from "@/app/docs/DocsNavigationProvider";
6-
import {PageTree} from "fumadocs-core/server";
5+
import * as PageTree from "fumadocs-core/page-tree";
76
import Link from "next/link";
87
import {usePathname} from "next/navigation";
98
import {ChevronDown} from "lucide-react";
109
import {cn} from "@/lib/utils";
1110
import {Collapsible, CollapsibleContent, CollapsibleTrigger,} from "@/components/ui/collapsible";
12-
import {ScrollArea, ScrollViewport} from "@/components/ui/scroll-area";
13-
import {useOnChange} from "fumadocs-core/utils/use-on-change";
1411
import { ncIsObject } from "@/utils/is";
1512

1613
interface FolderContextType {
@@ -28,40 +25,16 @@ const useFolderContext = () => {
2825
return context;
2926
};
3027

31-
interface InternalContext {
32-
level: number;
33-
isMobile?: boolean;
34-
closeSidebar?: () => void;
35-
}
36-
37-
const InternalContext = createContext<InternalContext | null>(null);
38-
39-
const useInternalContext = () => {
40-
const context = useContext(InternalContext);
41-
if (!context) {
42-
throw new Error("useInternalContext must be used within an InternalContext Provider");
43-
}
44-
return context;
45-
};
46-
4728
const Sidebar = ({isMobile}: {isMobile?: boolean}) => {
4829
const {root} = useTreeContext();
4930
const pathname = usePathname();
5031
const { setIsOpen } = useDocsNavigation();
5132

52-
const {open} = useSidebar()
53-
5433
const closeSidebar = useCallback(() => {
5534
if (isMobile) {
5635
setIsOpen(false);
5736
}
5837
}, [isMobile, setIsOpen]);
59-
60-
const context = useMemo<InternalContext>(() => ({
61-
level: 1,
62-
isMobile,
63-
closeSidebar
64-
}), [isMobile, closeSidebar]);
6538

6639
const children = useMemo(() => {
6740
function renderItems(items: PageTree.Node[], level: number) {
@@ -81,15 +54,11 @@ const Sidebar = ({isMobile}: {isMobile?: boolean}) => {
8154
}, [pathname]);
8255

8356
return (
84-
<InternalContext.Provider value={context}>
85-
<SidebarPrimitive.SidebarList removeScrollOn="(width < 768px)" className={cn("xl:flex sticky py-4 mr-3 flex-col shrink-0 ", open ? 'block' : 'hidden xl:block', isMobile ? 'block' : 'hidden top-[120px] h-[calc(100dvh-120px)] w-64')}>
86-
<ScrollArea className="h-full">
87-
<ScrollViewport>
88-
{children}
89-
</ScrollViewport>
90-
</ScrollArea>
91-
</SidebarPrimitive.SidebarList>
92-
</InternalContext.Provider>
57+
<div className={cn("xl:flex sticky py-4 mr-3 flex-col shrink-0 ", isMobile ? 'block' : 'hidden xl:block', isMobile ? 'w-64' : 'top-[120px] h-[calc(100dvh-120px)] w-64')}>
58+
<div className="flex flex-col gap-2">
59+
{children}
60+
</div>
61+
</div>
9362
);
9463
};
9564

@@ -99,14 +68,14 @@ function SidebarItem({item, children, level,}: {
9968
pathname: string;
10069
level: number;
10170
}) {
102-
const context = useInternalContext();
10371
const path = useTreePath();
104-
10572
const active = path.includes(item);
106-
73+
10774
const handleLinkClick = () => {
108-
if (context.closeSidebar) {
109-
context.closeSidebar();
75+
// Close sidebar on mobile navigation
76+
const sidebar = document.querySelector('[data-sidebar="sidebar"]');
77+
if (sidebar && window.innerWidth < 768) {
78+
// Mobile sidebar close logic will be handled by Shadcn sidebar
11079
}
11180
};
11281

@@ -122,7 +91,7 @@ function SidebarItem({item, children, level,}: {
12291
href={item.url}
12392
onClick={handleLinkClick}
12493
>
125-
{ncIsObject(item.icon) ? item.icon : ''}
94+
{ncIsObject(item.icon) ? item.icon : ''}
12695
{item.name}
12796
</Link>
12897
);
@@ -131,11 +100,12 @@ function SidebarItem({item, children, level,}: {
131100
if (item.type === "separator") {
132101
return (
133102
<p className="text-fd-muted-foreground mt-6 mb-2 first:mt-0">
134-
{ncIsObject(item.icon) ? item.icon : ''}
103+
{ncIsObject(item.icon) ? item.icon : ''}
135104
{item.name}
136105
</p>
137106
);
138107
}
108+
139109
if (item.type === "folder") {
140110
return (
141111
<SidebarFolder defaultOpen={(active || (item.defaultOpen ?? false))}>
@@ -148,14 +118,14 @@ function SidebarItem({item, children, level,}: {
148118
active
149119
? "text-nc-content-grey-emphasis"
150120
: "text-nc-content-grey-subtle-2 hover:bg-nc-background-grey-light"
151-
)}
152-
href={item.index.url}
153-
onClick={handleLinkClick}
154-
>
155-
{ncIsObject(item.index.icon) ? item.index.icon : ''}
156-
{item.index.name}
157-
</Link>
158-
</div>
121+
)}
122+
href={item.index.url}
123+
onClick={handleLinkClick}
124+
>
125+
{ncIsObject(item.index.icon) ? item.index.icon : ''}
126+
{item.index.name}
127+
</Link>
128+
</div>
159129
</SidebarFolderTrigger>
160130
) : (
161131
<SidebarFolderTrigger>
@@ -165,7 +135,7 @@ function SidebarItem({item, children, level,}: {
165135
active? "text-nc-content-grey-subtle-2 font-[600]" : ""
166136
)}
167137
>
168-
{ncIsObject(item.icon) ? item.icon : ''}
138+
{ncIsObject(item.icon) ? item.icon : ''}
169139
{item.name}
170140
</div>
171141
</SidebarFolderTrigger>
@@ -190,9 +160,9 @@ function SidebarFolder({defaultOpen = false, children}: {
190160
}) {
191161
const [open, setOpen] = useState(defaultOpen);
192162

193-
useOnChange(defaultOpen, (v) => {
194-
if (v) setOpen(v);
195-
});
163+
useEffect(() => {
164+
if (defaultOpen) setOpen(defaultOpen);
165+
}, [defaultOpen]);
196166

197167
return (
198168
<Collapsible open={open} onOpenChange={setOpen}>
@@ -227,19 +197,9 @@ function SidebarFolderTrigger({children}: { children: ReactNode }) {
227197
}
228198

229199
function SidebarFolderContent({children}: { children: ReactNode }) {
230-
const ctx = useInternalContext();
231-
232200
return (
233201
<CollapsibleContent>
234-
<InternalContext.Provider
235-
value={useMemo(() => ({
236-
level: ctx.level + 1,
237-
isMobile: ctx.isMobile,
238-
closeSidebar: ctx.closeSidebar
239-
}), [ctx.level, ctx.isMobile, ctx.closeSidebar])}
240-
>
241-
{children}
242-
</InternalContext.Provider>
202+
{children}
243203
</CollapsibleContent>
244204
);
245205
}

0 commit comments

Comments
 (0)