Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/app/[lang]/(home)/components/hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from '@/components/ui/command-prompt';

const COMMAND_FOR_HUMANS = 'npm install workflow';
const COMMAND_FOR_AGENTS = 'npx skills add vercel/workflow@workflow-init';
const COMMAND_FOR_AGENTS = 'npx skills add vercel/workflow';

type HeroProps = {
title: string;
Expand Down
8 changes: 8 additions & 0 deletions docs/app/[lang]/.well-known/mcp.json/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createMcpManifestRoute } from '@vercel/geistdocs/routes/mcp';
import { config } from '@/lib/geistdocs/config';

export const { GET, generateStaticParams, revalidate } = createMcpManifestRoute(
{
config,
}
);
6 changes: 6 additions & 0 deletions docs/app/[lang]/agents.md/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createAgentsRoute } from '@vercel/geistdocs/routes/agents';
import { config } from '@/lib/geistdocs/config';

export const { GET, generateStaticParams, revalidate } = createAgentsRoute({
config,
});
172 changes: 43 additions & 129 deletions docs/app/[lang]/cookbook/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,135 +1,49 @@
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import type { ComponentProps } from 'react';
import {
rewriteCookbookUrl,
rewriteCookbookUrlsInText,
} from '@/lib/geistdocs/cookbook-source';
import { MobileDocsBar } from '@/components/geistdocs/mobile-docs-bar';
import { AskAI } from '@/components/geistdocs/ask-ai';
import { CopyPage } from '@/components/geistdocs/copy-page';
import {
DocsBody,
DocsDescription,
DocsPage,
DocsTitle,
} from '@/components/geistdocs/docs-page';
import { EditSource } from '@/components/geistdocs/edit-source';
import { Feedback } from '@/components/geistdocs/feedback';
import { MobileDocsBar } from '@vercel/geistdocs/mobile-docs-bar';
import { createDocsPage } from '@vercel/geistdocs/pages/docs';
import type { ComponentProps, ComponentType } from 'react';
import { getMDXComponents } from '@/components/geistdocs/mdx-components';
import { OpenInChat } from '@/components/geistdocs/open-in-chat';
import { ScrollTop } from '@/components/geistdocs/scroll-top';
import { Badge } from '@/components/ui/badge';
import { Separator } from '@/components/ui/separator';
import { getLLMText, getPageImage, source } from '@/lib/geistdocs/source';

const Page = async ({ params }: PageProps<'/[lang]/cookbook/[[...slug]]'>) => {
const { slug, lang } = await params;

// Prepend 'cookbook' to resolve from the docs source
const resolvedSlug = slug ? ['cookbook', ...slug] : ['cookbook'];
const page = source.getPage(resolvedSlug, lang);

if (!page) {
notFound();
}

const publicUrl = rewriteCookbookUrl(page.url);
const publicPage = { ...page, url: publicUrl } as typeof page;

const markdown = rewriteCookbookUrlsInText(await getLLMText(page));
const MDX = page.data.body;

const RelativeLink = createRelativeLink(source, publicPage);
const PublicCookbookLink = (props: ComponentProps<typeof RelativeLink>) => {
const href =
typeof props.href === 'string'
? rewriteCookbookUrl(props.href)
: props.href;
return <RelativeLink {...props} href={href} />;
};

return (
<DocsPage
full={page.data.full}
tableOfContent={{
style: 'clerk',
footer: (
<div className="my-3 space-y-3">
<Separator />
<EditSource path={page.path} />
<ScrollTop />
<Feedback />
<CopyPage text={markdown} />
<AskAI href={publicUrl} />
<OpenInChat href={publicUrl} />
</div>
),
}}
tableOfContentPopover={{ enabled: false }}
toc={page.data.toc}
>
<MobileDocsBar toc={page.data.toc} />
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription>{page.data.description}</DocsDescription>
<DocsBody>
<MDX
components={getMDXComponents({
a: PublicCookbookLink,
Badge,
Step,
Steps,
Tabs,
Tab,
})}
/>
</DocsBody>
</DocsPage>
);
};

export const generateStaticParams = () => {
// Generate params for all cookbook pages
const allParams = source.generateParams();
return allParams
.filter((p) => Array.isArray(p.slug) && p.slug[0] === 'cookbook')
.map((p) => ({
...p,
slug: (p.slug as string[]).slice(1), // Remove 'cookbook' prefix
}));
};

export const generateMetadata = async ({
params,
}: PageProps<'/[lang]/cookbook/[[...slug]]'>) => {
const { slug, lang } = await params;
const resolvedSlug = slug ? ['cookbook', ...slug] : ['cookbook'];
const page = source.getPage(resolvedSlug, lang);

if (!page) {
notFound();
}

const publicPath = rewriteCookbookUrl(page.url);

const metadata: Metadata = {
title: page.data.title,
description: page.data.description,
openGraph: {
images: getPageImage(page).url,
},
import { config } from '@/lib/geistdocs/config';
import { rewriteCookbookUrl } from '@/lib/geistdocs/cookbook-source';
import { cookbookSource } from '@/lib/geistdocs/source';

const docsPage = createDocsPage({
config,
source: cookbookSource,
mdx: ({ link }) => getMDXComponents({ a: link }),
resolveLink: ({ link }) => {
const Link = link as ComponentType<ComponentProps<'a'>>;
const PublicCookbookLink = (props: ComponentProps<'a'>) => {
const href =
typeof props.href === 'string'
? rewriteCookbookUrl(props.href)
: props.href;

return <Link {...props} href={href} />;
};

return PublicCookbookLink;
},
openGraph: {
images: true,
},
tableOfContentPopover: {
enabled: false,
},
renderTop: ({ data }) => <MobileDocsBar toc={data.toc} />,
metadata: ({ metadata, page }) => ({
...metadata,
alternates: {
canonical: publicPath,
...metadata.alternates,
canonical: page.url,
types: {
'text/markdown': `${publicPath}.md`,
...metadata.alternates?.types,
'text/markdown':
page.url === '/cookbook' ? '/cookbook.md' : `${page.url}.md`,
},
},
};

return metadata;
};
}),
});

export default Page;
export default docsPage.Page;
export const generateStaticParams = docsPage.generateStaticParams;
export const generateMetadata = docsPage.generateMetadata;
8 changes: 7 additions & 1 deletion docs/app/[lang]/cookbook/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DocsLayout } from '@/components/geistdocs/docs-layout';
import { getCookbookTree } from '@/lib/geistdocs/cookbook-source';
import { LATEST_VERSION } from '@/lib/geistdocs/versions';

const Layout = async ({
children,
Expand All @@ -9,7 +10,12 @@ const Layout = async ({

return (
<div className="bg-background-100">
<DocsLayout tree={getCookbookTree(lang)}>{children}</DocsLayout>
<DocsLayout
currentVersion={LATEST_VERSION.id}
tree={getCookbookTree(lang)}
>
{children}
</DocsLayout>
</div>
);
};
Expand Down
153 changes: 26 additions & 127 deletions docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,134 +1,33 @@
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import type { Metadata } from 'next';
import { notFound, permanentRedirect } from 'next/navigation';
import { rewriteCookbookUrl } from '@/lib/geistdocs/cookbook-source';
import { AgentTraces } from '@/components/custom/agent-traces';
import { FluidComputeCallout } from '@/components/custom/fluid-compute-callout';
import { PreviewInstallServer } from '@/components/preview-install-server';
import { AskAI } from '@/components/geistdocs/ask-ai';
import { CopyPage } from '@/components/geistdocs/copy-page';
import {
DocsBody,
DocsDescription,
DocsPage,
DocsTitle,
} from '@/components/geistdocs/docs-page';
import { EditSource } from '@/components/geistdocs/edit-source';
import { Feedback } from '@/components/geistdocs/feedback';
import { MobileDocsBar } from '@vercel/geistdocs/mobile-docs-bar';
import { createDocsPage } from '@vercel/geistdocs/pages/docs';
import { getMDXComponents } from '@/components/geistdocs/mdx-components';
import { MobileDocsBar } from '@/components/geistdocs/mobile-docs-bar';
import { OpenInChat } from '@/components/geistdocs/open-in-chat';
import { ScrollTop } from '@/components/geistdocs/scroll-top';
import * as AccordionComponents from '@/components/ui/accordion';
import { Badge } from '@/components/ui/badge';
import { Separator } from '@/components/ui/separator';
import { getLLMText, getPageImage, source } from '@/lib/geistdocs/source';
import { TSDoc } from '@/lib/tsdoc';

// No-op component for world MDX files rendered outside /worlds/ context
// These pages redirect to /worlds/[id] but still get statically generated
const WorldTestingPerformanceNoop = () => null;

const Page = async ({ params }: PageProps<'/[lang]/docs/[[...slug]]'>) => {
const { slug, lang } = await params;

if (Array.isArray(slug) && slug[0] === 'cookbook') {
const rest = slug.slice(1).join('/');
const legacyPath = `/docs/cookbook${rest ? `/${rest}` : ''}`;
permanentRedirect(`/${lang}${rewriteCookbookUrl(legacyPath)}`);
}

const page = source.getPage(slug, lang);

if (!page) {
notFound();
}

const markdown = await getLLMText(page);
const MDX = page.data.body;

return (
<DocsPage
full={page.data.full}
tableOfContent={{
style: 'clerk',
footer: (
<div className="my-3 space-y-3">
<Separator />
<EditSource path={page.path} />
<ScrollTop />
<Feedback />
<CopyPage text={markdown} />
<AskAI href={page.url} />
<OpenInChat href={page.url} />
</div>
),
}}
tableOfContentPopover={{ enabled: false }}
toc={page.data.toc}
>
<MobileDocsBar toc={page.data.toc} />
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription>{page.data.description}</DocsDescription>
<DocsBody>
<MDX
components={getMDXComponents({
a: createRelativeLink(source, page),

// Add your custom components here
AgentTraces,
FluidComputeCallout,
Badge,
TSDoc,
Step,
Steps,
...AccordionComponents,
Tabs,
Tab,
PreviewInstall: PreviewInstallServer,
// No-op for world MDX files (they redirect to /worlds/[id])
WorldTestingPerformance: WorldTestingPerformanceNoop,
})}
/>
</DocsBody>
</DocsPage>
);
};

export const generateStaticParams = () =>
source
.generateParams()
.filter(
(params) => !(Array.isArray(params.slug) && params.slug[0] === 'cookbook')
);

export const generateMetadata = async ({
params,
}: PageProps<'/[lang]/docs/[[...slug]]'>) => {
const { slug, lang } = await params;
const page = source.getPage(slug, lang);

if (!page) {
notFound();
}

const metadata: Metadata = {
title: page.data.title,
description: page.data.description,
openGraph: {
images: getPageImage(page).url,
},
import { config } from '@/lib/geistdocs/config';
import { geistdocsSource } from '@/lib/geistdocs/source';

const docsPage = createDocsPage({
config,
source: geistdocsSource,
mdx: ({ link }) => getMDXComponents({ a: link }),
openGraph: {
images: true,
},
tableOfContentPopover: {
enabled: false,
},
renderTop: ({ data }) => <MobileDocsBar toc={data.toc} />,
metadata: ({ metadata, page }) => ({
...metadata,
alternates: {
...metadata.alternates,
canonical: page.url,
types: {
'text/markdown': `${page.url}.md`,
...metadata.alternates?.types,
'text/markdown': page.url === '/docs' ? '/docs.md' : `${page.url}.md`,
},
},
};

return metadata;
};
}),
});

export default Page;
export default docsPage.Page;
export const generateStaticParams = docsPage.generateStaticParams;
export const generateMetadata = docsPage.generateMetadata;
5 changes: 4 additions & 1 deletion docs/app/[lang]/docs/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ const Layout = async ({ children, params }: LayoutProps<'/[lang]/docs'>) => {

return (
<div className="bg-background-100">
<DocsLayout tree={getDocsTreeForVersion(lang, LATEST_VERSION)}>
<DocsLayout
currentVersion={LATEST_VERSION.id}
tree={getDocsTreeForVersion(lang, LATEST_VERSION)}
>
{children}
</DocsLayout>
</div>
Expand Down
Loading
Loading