@@ -10,8 +10,6 @@ import { notFound } from "next/navigation";
1010import defaultMdxComponents from "fumadocs-ui/mdx" ;
1111import { Badge } from "@/components/ui/badge" ;
1212import { CloudIcon } from "lucide-react" ;
13- import { getImageMeta } from "fumadocs-ui/og" ;
14-
1513import { Tabs , Tab } from "@/components/react/tabs" ;
1614import { Steps , Step } from "fumadocs-ui/components/steps" ;
1715import { TypeTable } from "fumadocs-ui/components/type-table" ;
@@ -25,6 +23,7 @@ import { InsecurePasswordProtected } from "@/components/react/insecure-password-
2523import { LinkToCopilotCloud } from "@/components/react/link-to-copilot-cloud" ;
2624import { Accordions , Accordion } from "fumadocs-ui/components/accordion" ;
2725import { NavigationLink } from "@/components/react/subdocs-menu" ;
26+ import { getSnippetTOCForPage } from "@/lib/snippet-toc" ;
2827
2928/**
3029 * TODO: This should be dynamic, but it's not working.
@@ -68,59 +67,88 @@ const mdxComponents = {
6867export default async function Page ( {
6968 params,
7069} : {
71- params : { slug ?: string [ ] } ;
70+ params : Promise < { slug ?: string [ ] } > ;
7271} ) {
73- const page = source . getPage ( params . slug ) ;
72+ const resolvedParams = await params ;
73+ const page = source . getPage ( resolvedParams . slug ) ;
7474 if ( ! page ) notFound ( ) ;
7575 const MDX = page . data . body ;
7676 const cloudOnly = cloudOnlyFeatures . includes ( page . data . title ) ;
77+
7778 // Consider a page "Premium" if its slug path contains a "premium" segment OR title matches known premium features OR frontmatter premium flag
7879 const bySlugPremium = Array . isArray ( page . slugs ) ? page . slugs . includes ( "premium" ) : false ;
7980 const byTitlePremium = premiumFeatureTitles . includes ( page . data . title || "" ) ;
8081 const byFrontmatterPremium = Boolean ( ( page as any ) . data ?. premium ) ;
8182 const isPremium = bySlugPremium || byTitlePremium || byFrontmatterPremium ;
8283 // Compute premium overview href based on current section (first slug segment)
8384 const baseSegment = Array . isArray ( page . slugs ) && page . slugs . length ? `/${ page . slugs [ 0 ] } ` : "/" ;
84- const premiumOverviewHref = baseSegment === "/" ? "/(root)/premium/overview" : `${ baseSegment } /premium/overview` ;
85-
85+ const premiumOverviewHref =
86+ baseSegment === "/" ? "/premium/overview" : `${ baseSegment } /premium/overview` ;
87+
88+ // Check if the page should hide the header or TOC
89+ const hideHeader = ( page . data as any ) . hideHeader || false ;
90+ const hideTOC = ( page . data as any ) . hideTOC || false ;
91+
92+ // Get TOC from imported snippets and merge with page TOC (only if TOC is not hidden)
93+ // Use try-catch to handle build-time issues gracefully
94+ let snippetTOC : any [ ] = [ ] ;
95+ if ( ! hideTOC ) {
96+ try {
97+ snippetTOC = await getSnippetTOCForPage ( resolvedParams . slug ) ;
98+ } catch ( error ) {
99+ console . warn ( 'Failed to load snippet TOC:' , error ) ;
100+ snippetTOC = [ ] ;
101+ }
102+ }
103+ const combinedTOC = hideTOC ? [ ] : [ ...( page . data . toc || [ ] ) , ...snippetTOC ] ;
104+
86105 return (
87106 < DocsPage
88- toc = { [ ] }
107+ toc = { combinedTOC }
89108 full = { page . data . full }
109+ tableOfContent = { {
110+ style :"clerk" ,
111+ } }
90112 >
91- < div className = "flex items-center gap-3" >
92- < DocsTitle className = "flex items-center" >
93- { page . data . title }
94- { cloudOnly && (
95- < Badge
96- variant = "secondary"
97- className = "ml-3 mt-1 inline-flex items-center gap-1.5 py-1.5 px-3 bg-indigo-600/90 text-white hover:bg-indigo-600 border-0 rounded-md transition-colors"
98- >
99- < CloudIcon className = "w-3 h-3" />
100- < span className = "text-xs" > Cloud Only</ span >
101- </ Badge >
102- ) }
103- { isPremium && (
104- < a href = { premiumOverviewHref } className = "ml-3 mt-1" >
105- < Badge
106- variant = "secondary"
107- className = "inline-flex items-center gap-2 py-2 px-3.5 bg-indigo-100 text-indigo-700 dark:bg-indigo-900/40 dark:text-indigo-200 hover:bg-indigo-200 border-0 rounded-md transition-colors"
108- >
109- < img
110- src = "https://cdn.copilotkit.ai/docs/copilotkit/images/copilotkit-logo.svg"
111- alt = "CopilotKit"
112- className = "w-5 h-5"
113- />
114- < span className = "text-sm font-semibold tracking-tight" > Premium</ span >
115- </ Badge >
116- </ a >
117- ) }
118- </ DocsTitle >
113+ < div className = { hideHeader ? "" : "min-h-screen" } >
114+ { ! hideHeader && (
115+ < >
116+ < div className = "flex items-center gap-3" >
117+ < DocsTitle className = "flex items-center mb-2" >
118+ { page . data . title }
119+ { cloudOnly && (
120+ < Badge
121+ variant = "secondary"
122+ className = "ml-3 mt-1 inline-flex items-center gap-1.5 py-1.5 px-3 bg-indigo-600/90 text-white hover:bg-indigo-600 border-0 rounded-md transition-colors"
123+ >
124+ < CloudIcon className = "w-3 h-3" />
125+ < span className = "text-xs" > Cloud Only</ span >
126+ </ Badge >
127+ ) }
128+ { isPremium && (
129+ < a href = { premiumOverviewHref } className = "ml-3" >
130+ < Badge
131+ variant = "secondary"
132+ className = "inline-flex items-center gap-2 py-2 px-3.5 bg-indigo-100 text-indigo-700 dark:bg-indigo-900/40 dark:text-indigo-200 hover:bg-indigo-200 border-0 rounded-md transition-colors"
133+ >
134+ < img
135+ src = "https://cdn.copilotkit.ai/docs/copilotkit/icons/copilotkit-color.svg"
136+ alt = "CopilotKit"
137+ className = "w-4 h-4"
138+ />
139+ < span className = "text-sm font-semibold tracking-tight" > Premium</ span >
140+ </ Badge >
141+ </ a >
142+ ) }
143+ </ DocsTitle >
144+ </ div >
145+ < DocsDescription > { page . data . description } </ DocsDescription >
146+ </ >
147+ ) }
148+ < DocsBody >
149+ < MDX components = { mdxComponents } />
150+ </ DocsBody >
119151 </ div >
120- < DocsDescription > { page . data . description } </ DocsDescription >
121- < DocsBody >
122- < MDX components = { mdxComponents } renderSmth = { ( ) => < div > test</ div > } />
123- </ DocsBody >
124152 </ DocsPage >
125153 ) ;
126154}
@@ -129,21 +157,13 @@ export async function generateStaticParams() {
129157 return source . generateParams ( ) ;
130158}
131159
132- export function generateMetadata ( { params } : { params : { slug ?: string [ ] } } ) {
133- const page = source . getPage ( params . slug ) ;
160+ export async function generateMetadata ( { params } : { params : Promise < { slug ?: string [ ] } > } ) {
161+ const resolvedParams = await params ;
162+ const page = source . getPage ( resolvedParams . slug ) ;
134163 if ( ! page ) notFound ( ) ;
135164
136- const image = getImageMeta ( "og" , page . slugs ) ;
137-
138165 return {
139166 title : page . data . title ,
140167 description : page . data . description ,
141- openGraph : {
142- images : image ,
143- } ,
144- twitter : {
145- images : image ,
146- card : "summary_large_image" ,
147- } ,
148168 } satisfies Metadata ;
149169}
0 commit comments