Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
127 changes: 66 additions & 61 deletions app/(docs)/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,78 @@
import { getPageMarkdownUrl, source } from '@/lib/source';
import { getPageMarkdownUrl, source } from "@/lib/source";
import {
DocsBody,
DocsDescription,
DocsPage,
DocsTitle,
MarkdownCopyButton,
ViewOptionsPopover,
} from 'fumadocs-ui/layouts/docs/page';
import { notFound } from 'next/navigation';
import { getMDXComponents } from '@/components/mdx';
import type { Metadata } from 'next';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import { appName, gitConfig, socialImage } from '@/lib/shared';
DocsBody,
DocsDescription,
DocsPage,
DocsTitle,
MarkdownCopyButton,
ViewOptionsPopover,
} from "fumadocs-ui/layouts/docs/page";
import { notFound } from "next/navigation";
import { getMDXComponents } from "@/components/mdx";
import type { Metadata } from "next";
import { createRelativeLink } from "fumadocs-ui/mdx";
import { appName, gitConfig, socialImage, appDescription } from "@/lib/shared";

export default async function Page(props: PageProps<'/[[...slug]]'>) {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) notFound();
export default async function Page(props: PageProps<"/[[...slug]]">) {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) notFound();

const MDX = page.data.body;
const markdownUrl = getPageMarkdownUrl(page).url;
const MDX = page.data.body;
const markdownUrl = getPageMarkdownUrl(page).url;

return (
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription className="mb-0">{page.data.description}</DocsDescription>
<div className="flex flex-row gap-2 items-center border-b pb-6">
<MarkdownCopyButton markdownUrl={markdownUrl} />
<ViewOptionsPopover
markdownUrl={markdownUrl}
githubUrl={`https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/content/docs/${page.path}`}
/>
</div>
<DocsBody>
<MDX
components={getMDXComponents({
// this allows you to link to other pages with relative file paths
a: createRelativeLink(source, page),
})}
/>
</DocsBody>
</DocsPage>
);
return (
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription className="mb-0">
{page.data.description}
</DocsDescription>
<div className="flex flex-row gap-2 items-center border-b pb-6">
<MarkdownCopyButton markdownUrl={markdownUrl} />
<ViewOptionsPopover
markdownUrl={markdownUrl}
githubUrl={`https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/content/docs/${page.path}`}
/>
</div>
<DocsBody>
<MDX
components={getMDXComponents({
a: createRelativeLink(source, page),
})}
/>
</DocsBody>
</DocsPage>
);
}

export async function generateStaticParams() {
return source.generateParams();
return source.generateParams();
}

export async function generateMetadata(props: PageProps<'/[[...slug]]'>): Promise<Metadata> {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) notFound();
export async function generateMetadata(
props: PageProps<"/[[...slug]]">,
): Promise<Metadata> {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) notFound();

// Mirrors the old VuePress `dynamic-meta-plugin`: "<page title> | Custom Command".
const social = page.data.title ? `${page.data.title} | ${appName}` : `${appName} Documentation`;
const social = page.data.title
? `${page.data.title} | ${appName}`
: `${appName} Documentation`;

return {
title: page.data.title,
description: page.data.description,
openGraph: {
title: social,
description: page.data.description,
images: socialImage,
},
twitter: {
title: social,
description: page.data.description,
images: socialImage,
},
};
return {
title: page.data.title,
description: appDescription,
openGraph: {
title: social,
description: appDescription,
images: socialImage,
},
twitter: {
card: "summary",
title: social,
description: appDescription,
images: socialImage,
},
};
}
18 changes: 9 additions & 9 deletions app/(docs)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { source } from '@/lib/source';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/lib/layout.shared';
import { source } from "@/lib/source";
import { DocsLayout } from "fumadocs-ui/layouts/docs";
import { baseOptions } from "@/lib/layout.shared";

export default function Layout({ children }: LayoutProps<'/'>) {
return (
<DocsLayout tree={source.getPageTree()} {...baseOptions()}>
{children}
</DocsLayout>
);
export default function Layout({ children }: LayoutProps<"/">) {
return (
<DocsLayout tree={source.getPageTree()} {...baseOptions()}>
{children}
</DocsLayout>
);
}
64 changes: 32 additions & 32 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
import { Inter } from 'next/font/google';
import type { Metadata, Viewport } from 'next';
import { Provider } from '@/components/provider';
import { appDescription, appName, siteUrl, socialImage } from '@/lib/shared';
import './global.css';
import { Inter } from "next/font/google";
import type { Metadata, Viewport } from "next";
import { Provider } from "@/components/provider";
import { appDescription, appName, siteUrl, socialImage } from "@/lib/shared";
import "./global.css";

const inter = Inter({
subsets: ['latin'],
subsets: ["latin"],
});

export const metadata: Metadata = {
metadataBase: new URL(siteUrl),
title: {
// Matches the old VuePress `dynamic-meta-plugin` output.
template: `%s | ${appName}`,
default: `${appName} Documentation`,
},
description: appDescription,
icons: {
icon: socialImage,
},
openGraph: {
metadataBase: new URL(siteUrl),
title: {
template: `%s | ${appName}`,
default: `${appName} Documentation`,
},
description: appDescription,
images: socialImage,
},
twitter: {
description: appDescription,
images: socialImage,
},
icons: {
icon: socialImage,
},
openGraph: {
description: appDescription,
images: socialImage,
},
twitter: {
card: "summary",
description: appDescription,
images: socialImage,
},
};

export const viewport: Viewport = {
themeColor: '#74b0f7',
themeColor: "#74b0f7",
};

export default function Layout({ children }: LayoutProps<'/'>) {
return (
<html lang="en" className={inter.className} suppressHydrationWarning>
<body className="flex flex-col min-h-screen">
<Provider>{children}</Provider>
</body>
</html>
);
export default function Layout({ children }: LayoutProps<"/">) {
return (
<html lang="en" className={inter.className} suppressHydrationWarning>
<body className="flex flex-col min-h-screen">
<Provider>{children}</Provider>
</body>
</html>
);
}
49 changes: 49 additions & 0 deletions components/image-zoom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client';

import { Image, type ImageProps } from 'fumadocs-core/framework';
import type { ComponentProps } from 'react';
import Zoom, { type UncontrolledProps } from 'react-medium-image-zoom';
import '../styles/image-zoom.css';

export type ImageZoomProps = ImageProps & {
/**
* Image props when zoom in
*/
zoomInProps?: ComponentProps<'img'>;

/**
* Props for `react-medium-image-zoom`
*/
rmiz?: UncontrolledProps;
};

function getImageSrc(src: ImageProps['src']): string {
if (typeof src === 'string') return src;

if (typeof src === 'object') {
// Next.js
if ('default' in src) return (src as { default: { src: string } }).default.src;
return src.src;
}

return '';
}

export function ImageZoom({ zoomInProps, children, rmiz, ...props }: ImageZoomProps) {
return (
<Zoom
zoomMargin={20}
wrapElement="span"
{...rmiz}
zoomImg={{
src: getImageSrc(props.src),
sizes: undefined,
...zoomInProps,
}}
>
{children ?? (
<Image sizes="(max-width: 768px) 100vw, (max-width: 1200px) 70vw, 900px" {...props} />
)}
</Zoom>
);
}
Loading