Skip to content

Commit 66694d7

Browse files
authored
Merge pull request #15 from fellipeutaka/next
Next
2 parents ac16040 + 7ecb6d7 commit 66694d7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+4768
-2943
lines changed

apps/www/.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,5 @@ yarn-error.log*
3939
*.tsbuildinfo
4040
next-env.d.ts
4141

42-
# mdx files (velite)
43-
.velite
42+
# mdx files (fumadocs)
43+
.source

apps/www/next.config.js renamed to apps/www/next.config.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
1-
// @ts-check
1+
import { createMDX } from "fumadocs-mdx/next";
2+
import type { NextConfig } from "next";
23

3-
const isDev = process.argv.indexOf("dev") !== -1;
4-
const isBuild = process.argv.indexOf("build") !== -1;
5-
if (!process.env.VELITE_STARTED && (isDev || isBuild)) {
6-
process.env.VELITE_STARTED = "1";
7-
const { build } = await import("velite");
8-
await build({ watch: isDev, clean: !isDev });
9-
}
4+
const withMDX = createMDX();
105

11-
/** @type {import('next').NextConfig} */
12-
const config = {
6+
const config: NextConfig = {
137
reactStrictMode: true,
148
eslint: {
159
ignoreDuringBuilds: true,
@@ -44,4 +38,4 @@ const config = {
4438
},
4539
};
4640

47-
export default config;
41+
export default withMDX(config);

apps/www/package.json

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,51 @@
33
"type": "module",
44
"private": true,
55
"scripts": {
6+
"postinstall": "fumadocs-mdx",
67
"dev": "next dev --turbopack",
78
"build": "next build",
89
"start": "next start",
910
"preview": "next build && next start",
1011
"type-check": "tsc --noEmit --incremental false"
1112
},
1213
"dependencies": {
14+
"@fumadocs/mdx-remote": "^1.2.0",
1315
"@hookform/resolvers": "^4.1.3",
1416
"@internationalized/date": "^3.7.0",
1517
"@radix-ui/react-scroll-area": "^1.2.3",
16-
"@react-stately/data": "^3.12.1",
17-
"@tanstack/react-form": "^1.0.0",
18+
"@react-stately/data": "^3.12.2",
19+
"@tanstack/react-form": "^1.0.5",
20+
"@tanstack/react-query": "^5.67.2",
1821
"@vercel/analytics": "^1.5.0",
1922
"@vercel/speed-insights": "^1.2.0",
20-
"cmdk": "^1.0.4",
21-
"motion": "^12.4.10",
23+
"fumadocs-core": "^15.0.15",
24+
"motion": "^12.4.11",
2225
"next": "^15.2.1",
23-
"next-themes": "^0.4.4",
26+
"next-themes": "0.4.4",
2427
"react": "^19.0.0",
25-
"react-aria-components": "^1.6.0",
28+
"react-aria-components": "^1.7.1",
2629
"react-dom": "^19.0.0",
2730
"react-hook-form": "^7.54.2",
2831
"recharts": "^2.15.1",
32+
"shiki": "^3.1.0",
2933
"sonner": "^2.0.1",
3034
"zod": "^3.24.2"
3135
},
3236
"devDependencies": {
3337
"@kanpeki/tsconfig": "workspace:*",
34-
"@tailwindcss/postcss": "^4.0.9",
38+
"@tailwindcss/postcss": "^4.0.12",
39+
"@types/mdx": "^2.0.13",
3540
"@types/react": "^19.0.10",
3641
"@types/react-dom": "^19.0.4",
3742
"@types/unist": "^3.0.3",
3843
"cva": "1.0.0-beta.3",
44+
"fumadocs-mdx": "^11.5.6",
3945
"postcss": "^8.5.3",
40-
"rehype-pretty-code": "^0.14.0",
41-
"rehype-slug": "^6.0.0",
4246
"tailwind-merge": "^3.0.2",
43-
"tailwindcss": "^4.0.9",
47+
"tailwindcss": "^4.0.12",
4448
"tailwindcss-motion": "^1.1.0",
45-
"tailwindcss-react-aria-components": "nightly",
49+
"tailwindcss-react-aria-components": "^2.0.0",
4650
"unist-builder": "^4.0.0",
47-
"unist-util-visit": "^5.0.0",
48-
"velite": "^0.2.2"
51+
"unist-util-visit": "^5.0.0"
4952
}
5053
}

apps/www/source.config.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { rehypeCodeDefaultOptions } from "fumadocs-core/mdx-plugins";
2+
import { defineConfig, defineDocs } from "fumadocs-mdx/config";
3+
import { z } from "zod";
4+
import { rehypeComponent } from "~/lib/mdx-plugins/rehype-component";
5+
import { transformerNpmCommands } from "~/lib/mdx-plugins/rehype-npm-commands";
6+
import { vercelDarkTheme } from "~/styles/vercel-dark";
7+
import { vercelLightTheme } from "~/styles/vercel-light";
8+
9+
export const docs = defineDocs({
10+
dir: "src/content/docs",
11+
docs: {
12+
schema: z.object({
13+
title: z.string().max(32),
14+
description: z.string().max(256),
15+
links: z
16+
.object({
17+
docs: z.string().url(),
18+
api: z.string().url(),
19+
})
20+
.partial()
21+
.optional(),
22+
}),
23+
// TODO: Wait to async be not experimental: https://fumadocs.vercel.app/docs/mdx/async
24+
// async: true,
25+
},
26+
});
27+
28+
export default defineConfig({
29+
lastModifiedTime: "git",
30+
mdxOptions: {
31+
rehypeCodeOptions: {
32+
themes: {
33+
light: vercelLightTheme,
34+
dark: vercelDarkTheme,
35+
},
36+
icon: false,
37+
transformers: [
38+
...(rehypeCodeDefaultOptions.transformers ?? []),
39+
transformerNpmCommands(),
40+
],
41+
},
42+
rehypePlugins: (v) => [rehypeComponent, ...v],
43+
},
44+
});

apps/www/src/@types/unist.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export interface UnistNode extends Node {
1010
__className__?: string;
1111
__event__?: string;
1212
[key: string]: unknown;
13-
} & NpmCommands;
13+
};
1414
attributes?: {
1515
name: string;
1616
value: unknown;
@@ -25,10 +25,3 @@ export interface UnistNode extends Node {
2525
export interface UnistTree extends Node {
2626
children: UnistNode[];
2727
}
28-
29-
export interface NpmCommands {
30-
__npmCommand__?: string;
31-
__yarnCommand__?: string;
32-
__pnpmCommand__?: string;
33-
__bunCommand__?: string;
34-
}

apps/www/src/app/_components/hero-section.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function HeroSection() {
2929
Accessible, flexible, mobile friendly, modern UI components.
3030
</p>
3131
<div className="flex flex-col gap-4 sm:flex-row">
32-
<LinkButton href="/docs/introduction" size="lg">
32+
<LinkButton href="/docs" size="lg">
3333
Get Started
3434
</LinkButton>
3535
<LinkButton
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { createFromSource } from "fumadocs-core/search/server";
2+
import { source } from "~/lib/source";
3+
4+
export const { GET } = createFromSource(source);

apps/www/src/app/docs/[[...slug]]/_components/contribute.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import { Icons } from "~/components/ui/icons";
22
import { Link } from "~/components/ui/link/link";
33
import { getGitHubIssueUrl, getGithubFileUrl } from "~/utils/github";
4-
import type { Doc } from "~/utils/mdx";
54

65
interface ContributeProps {
7-
doc: Doc;
6+
url: string;
7+
path: string;
88
}
99

10-
export function Contribute({ doc }: ContributeProps) {
10+
export function Contribute({ url, path }: ContributeProps) {
1111
const contributeLinks = [
1212
{
1313
text: "Report an issue",
1414
icon: Icons.Bug,
1515
href: getGitHubIssueUrl({
1616
owner: "fellipeutaka",
1717
repo: "kanpeki",
18-
title: `[bug]: ${doc.slugAsParams}`,
18+
title: `[bug]: ${url}`,
1919
labels: ["bug", "documentation"],
2020
template: "bug_report.md",
2121
}),
@@ -26,15 +26,15 @@ export function Contribute({ doc }: ContributeProps) {
2626
href: getGitHubIssueUrl({
2727
owner: "fellipeutaka",
2828
repo: "kanpeki",
29-
title: `[feat]: ${doc.slugAsParams}`,
29+
title: `[feat]: ${url}`,
3030
labels: ["enhancement"],
3131
template: "feature_request.md",
3232
}),
3333
},
3434
{
3535
text: "Edit this page",
3636
icon: Icons.Pencil,
37-
href: getGithubFileUrl(doc.slug),
37+
href: getGithubFileUrl(path),
3838
},
3939
];
4040

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,37 @@
1-
"use client";
2-
1+
import { getBreadcrumbItems } from "fumadocs-core/breadcrumb";
32
import { Fragment } from "react";
43
import { Breadcrumb } from "~/components/ui/breadcrumb";
5-
import type { Doc } from "~/utils/mdx";
6-
7-
function formatTitle(title: string) {
8-
return title.replace(/-/g, " ");
9-
}
4+
import { source } from "~/lib/source";
105

116
interface DocsBreadcrumbProps {
12-
doc: Doc;
7+
url: string;
138
}
149

15-
export function DocsBreadcrumb({ doc }: DocsBreadcrumbProps) {
16-
if (doc.title === "Introduction") {
17-
return null;
18-
}
10+
export function DocsBreadcrumb({ url }: DocsBreadcrumbProps) {
11+
const items = getBreadcrumbItems(url, source.pageTree);
1912

2013
return (
2114
<Breadcrumb.Root className="mb-4 gap-1 sm:gap-1">
2215
<Breadcrumb.Item>
2316
<Breadcrumb.Link href="/docs">Docs</Breadcrumb.Link>
2417
</Breadcrumb.Item>
2518
<Breadcrumb.Separator />
26-
{doc.slugAsParams
27-
.split("/")
28-
.slice(0, -1)
29-
.map((link) => (
30-
<Fragment key={link}>
19+
{items.map((item, index) => {
20+
const url = item.url ?? "/docs/components";
21+
22+
return (
23+
<Fragment key={url}>
3124
<Breadcrumb.Item>
32-
<Breadcrumb.Link href={`/docs/${link}`} className="capitalize">
33-
{formatTitle(link)}
34-
</Breadcrumb.Link>
25+
{index === items.length - 1 ? (
26+
<Breadcrumb.Page>{item.name}</Breadcrumb.Page>
27+
) : (
28+
<Breadcrumb.Link href={url}>{item.name}</Breadcrumb.Link>
29+
)}
3530
</Breadcrumb.Item>
36-
<Breadcrumb.Separator />
31+
{index < items.length - 1 && <Breadcrumb.Separator />}
3732
</Fragment>
38-
))}
39-
<Breadcrumb.Item>
40-
<Breadcrumb.Page>{doc.title}</Breadcrumb.Page>
41-
</Breadcrumb.Item>
33+
);
34+
})}
4235
</Breadcrumb.Root>
4336
);
4437
}

apps/www/src/app/docs/[[...slug]]/_components/docs-header.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,47 @@
11
import { BadgeStyles } from "~/components/ui/badge/styles";
22
import { LinkButton } from "~/components/ui/button";
33
import { Icons } from "~/components/ui/icons";
4-
import type { Doc } from "~/utils/mdx";
4+
import type { source } from "~/lib/source";
55
import { DocsBreadcrumb } from "./docs-breadcrumb";
66

77
interface DocsHeaderProps {
8-
doc: Doc;
8+
page: NonNullable<ReturnType<(typeof source)["getPage"]>>;
99
}
1010

11-
export function DocsHeader({ doc }: DocsHeaderProps) {
11+
export function DocsHeader({ page }: DocsHeaderProps) {
12+
const { data, url } = page;
13+
1214
return (
1315
<>
14-
<DocsBreadcrumb doc={doc} />
16+
<DocsBreadcrumb url={url} />
1517
<div className="space-y-2">
16-
<h1 className="scroll-m-20 font-bold text-3xl tracking-tight">
17-
{doc.title}
18+
<h1 className="scroll-m-20 break-words font-bold text-3xl tracking-tight">
19+
{data.title}
1820
</h1>
1921
<p className="text-balance text-base text-muted-fg">
20-
{doc.description}
22+
{data.description}
2123
</p>
2224
</div>
23-
{doc.links && (
25+
{data.links && (
2426
<div className="mt-4 flex items-center gap-x-2">
25-
{doc.links?.docs && (
27+
{data.links?.docs && (
2628
<LinkButton
27-
href={doc.links.docs}
29+
href={data.links.docs}
2830
target="_blank"
2931
rel="noopener noreferrer"
3032
className={BadgeStyles({
3133
variant: "secondary",
3234
className: "h-auto gap-1.5",
3335
})}
3436
>
35-
<DocsLinkIcon link={doc.links.docs} />
37+
<DocsLinkIcon link={data.links.docs} />
3638
Docs
3739
<Icons.ExternalLink className="size-3" />
3840
</LinkButton>
3941
)}
40-
{doc.links?.api && (
42+
{data.links?.api && (
4143
<LinkButton
42-
href={doc.links.api}
44+
href={data.links.api}
4345
target="_blank"
4446
rel="noopener noreferrer"
4547
className={BadgeStyles({

0 commit comments

Comments
 (0)