Skip to content

Commit

Permalink
Core: Support referencing original page/meta from page tree nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
fuma-nama committed Sep 17, 2024
1 parent b0bd94b commit 367f4c3
Show file tree
Hide file tree
Showing 25 changed files with 346 additions and 87 deletions.
5 changes: 5 additions & 0 deletions .changeset/eighty-weeks-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'fumadocs-ui': patch
---

Improve Root Toggle component
5 changes: 5 additions & 0 deletions .changeset/gentle-wolves-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'fumadocs-core': minor
---

Support referencing original page/meta from page tree nodes
10 changes: 5 additions & 5 deletions apps/docs/app/docs/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { TypeTable } from 'fumadocs-ui/components/type-table';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
import Preview from '@/components/preview';
import { createMetadata, metadataImage } from '@/utils/metadata';
import { openapi, utils } from '@/app/source';
import { openapi, source } from '@/app/source';
import { Wrapper } from '@/components/preview/wrapper';

interface Param {
Expand All @@ -28,7 +28,7 @@ export default function Page({
}: {
params: Param;
}): React.ReactElement {
const page = utils.getPage(params.slug);
const page = source.getPage(params.slug);

if (!page) notFound();

Expand Down Expand Up @@ -75,15 +75,15 @@ export default function Page({
}}
/>
{page.data.index ? (
<DocsCategory page={page} pages={utils.getPages()} />
<DocsCategory page={page} pages={source.getPages()} />
) : null}
</DocsBody>
</DocsPage>
);
}

export function generateMetadata({ params }: { params: Param }): Metadata {
const page = utils.getPage(params.slug);
const page = source.getPage(params.slug);

if (!page) notFound();

Expand All @@ -102,5 +102,5 @@ export function generateMetadata({ params }: { params: Param }): Metadata {
}

export function generateStaticParams(): Param[] {
return utils.generateParams();
return source.generateParams();
}
75 changes: 58 additions & 17 deletions apps/docs/app/layout.config.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { type DocsLayoutProps } from 'fumadocs-ui/layouts/docs';
import { AlbumIcon, BookIcon, Heart, LayoutTemplateIcon } from 'lucide-react';
import Image from 'next/image';
import { RootToggle } from 'fumadocs-ui/components/layout/root-toggle';
import {
type Option,
RootToggle,
} from 'fumadocs-ui/components/layout/root-toggle';
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
import { type PageTree } from 'fumadocs-core/server';
import { Slot } from '@radix-ui/react-slot';
import { FumadocsIcon } from '@/app/layout.client';
import Logo from '@/public/logo.png';
import { utils } from '@/app/source';
import { source } from '@/app/source';
import { modes } from '@/utils/modes';

export const baseOptions: BaseLayoutProps = {
Expand Down Expand Up @@ -58,9 +63,42 @@ export const baseOptions: BaseLayoutProps = {
],
};

function getItems(): Option[] {
const options: Option[] = [];

function traverse(node: PageTree.Node): void {
if (node.type === 'folder' && node.root && node.index) {
const meta = source.getNodeMeta(node);
if (!meta) return;

options.push({
url: node.index.url,
icon: (
<Slot
className="mb-auto bg-gradient-to-t from-fd-background/80 p-1 [&_svg]:size-5"
style={{
color: `hsl(var(--${meta.file.dirname}-color))`,
backgroundColor: `hsl(var(--${meta.file.dirname}-color)/.3)`,
}}
>
{node.icon}
</Slot>
),
description: meta.data.description,
title: node.name,
});
}

if (node.type === 'folder') node.children.forEach(traverse);
}

source.pageTree.children.forEach(traverse);
return options;
}

export const docsOptions: DocsLayoutProps = {
...baseOptions,
tree: utils.pageTree,
tree: source.pageTree,
nav: {
...baseOptions.nav,
transparentMode: 'none',
Expand All @@ -70,20 +108,23 @@ export const docsOptions: DocsLayoutProps = {
sidebar: {
banner: (
<RootToggle
options={modes.map((mode) => ({
url: `/docs/${mode.param}`,
icon: (
<mode.icon
className="size-9 shrink-0 rounded-md bg-gradient-to-t from-fd-background/80 p-1.5"
style={{
backgroundColor: `hsl(var(--${mode.param}-color)/.3)`,
color: `hsl(var(--${mode.param}-color))`,
}}
/>
),
title: mode.name,
description: mode.description,
}))}
options={
getItems() ||
modes.map((mode) => ({
url: `/docs/${mode.param}`,
icon: (
<mode.icon
className="size-9 shrink-0 rounded-md bg-gradient-to-t from-fd-background/80 p-1.5"
style={{
backgroundColor: `hsl(var(--${mode.param}-color)/.3)`,
color: `hsl(var(--${mode.param}-color))`,
}}
/>
),
title: mode.name,
description: mode.description,
}))
}
/>
),
},
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { MetadataRoute } from 'next';
import { baseUrl } from '@/utils/metadata';
import { utils } from '@/app/source';
import { source } from '@/app/source';

export default function sitemap(): MetadataRoute.Sitemap {
const url = (path: string): string => new URL(path, baseUrl).toString();
Expand All @@ -21,7 +21,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: 'monthly',
priority: 0.8,
},
...utils.getPages().map<MetadataRoute.Sitemap[number]>((page) => ({
...source.getPages().map<MetadataRoute.Sitemap[number]>((page) => ({
url: url(page.url),
lastModified: page.data.lastModified
? new Date(page.data.lastModified)
Expand Down
15 changes: 9 additions & 6 deletions apps/docs/app/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import type { InferMetaType, InferPageType } from 'fumadocs-core/source';
import { loader } from 'fumadocs-core/source';
import { icons } from 'lucide-react';
import { attachFile, createOpenAPI } from 'fumadocs-openapi/server';
import { create } from '@/components/ui/icon';
import { createElement } from 'react';
import { IconContainer } from '@/components/ui/icon';
import { meta, docs, blog as blogPosts } from '@/.source';

export const utils = loader({
export const source = loader({
baseUrl: '/docs',
icon(icon) {
if (icon && icon in icons)
return create({ icon: icons[icon as keyof typeof icons] });
return createElement(IconContainer, {
icon: icons[icon as keyof typeof icons],
});
},
source: createMDXSource(docs, meta),
pageTree: {
Expand All @@ -23,7 +26,7 @@ export const blog = loader({
source: createMDXSource(blogPosts, []),
});

export const openapi = createOpenAPI({});
export const openapi = createOpenAPI();

export type Page = InferPageType<typeof utils>;
export type Meta = InferMetaType<typeof utils>;
export type Page = InferPageType<typeof source>;
export type Meta = InferMetaType<typeof source>;
4 changes: 2 additions & 2 deletions apps/docs/app/static.json/route.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { NextResponse } from 'next/server';
import { type DocumentRecord } from 'fumadocs-core/search/algolia';
import { utils } from '@/app/source';
import { source } from '@/app/source';

export const revalidate = false;

export function GET(): Response {
const results: DocumentRecord[] = [];
const pages = utils.getPages();
const pages = source.getPages();

for (const page of pages) {
results.push({
Expand Down
15 changes: 12 additions & 3 deletions apps/docs/components/ui/icon.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import type { LucideIcon } from 'lucide-react';
import { TerminalIcon } from 'lucide-react';
import { type HTMLAttributes } from 'react';
import { cn } from '@/utils/cn';

export function create({
export function IconContainer({
icon: Icon,
}: {
...props
}: HTMLAttributes<HTMLDivElement> & {
icon?: LucideIcon;
}): React.ReactElement {
return (
<div className="rounded-md border bg-gradient-to-b from-fd-secondary p-1 shadow-sm">
<div
{...props}
className={cn(
'rounded-md border bg-gradient-to-b from-fd-secondary p-1 shadow-sm',
props.className,
)}
>
{Icon ? <Icon /> : <TerminalIcon />}
</div>
);
Expand Down
92 changes: 92 additions & 0 deletions apps/docs/content/docs/cli/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
title: User Guide
description: The CLI tool that automates setups and installing components.
---

## Installation

The CLI doesn't need to install any extra packages, but It needs Fumadocs Core for minimal setup.

You can initialize a config for CLI.

```package-install
npx fumadocs config
```

It defines the output paths of components.

### Components

Select and install components.

```package-install
npx fumadocs add
```

You can pass component names.

```package-install
npx fumadocs add banner files
```

#### How the magic works?

The CLI fetches the latest version of component from the GitHub repository of Fumadocs.
When you install the component, it is guaranteed to be up-to-date.

In addition, it also transforms import paths.
Make sure to use the latest version of CLI

> This is highly Inspired by Shadcn UI.
### Tree

Generate files tree for Fumadocs UI `Files` component, using the `tree` command from your terminal.

```package-install
npx fumadocs tree ./my-dir ./output.tsx
```

You can output MDX file too:

```package-install
npx fumadocs tree ./my-dir ./output.mdx
```

See help for further details:

```package-install
npx fumadocs tree -h
```

#### Example Output

```tsx title="output.tsx"
import { File, Folder, Files } from 'fumadocs-ui/components/files';

export default (
<Files>
<Folder name="app">
<File name="layout.tsx" />
<File name="page.tsx" />
<File name="global.css" />
</Folder>
<Folder name="components">
<File name="button.tsx" />
<File name="tabs.tsx" />
<File name="dialog.tsx" />
</Folder>
<File name="package.json" />
</Files>
);
```

### Initialize Features

Some features of Fumadocs require copying code to get started, it is similar to `codemod` but for configuring features automatically.

```package-install
npx fumadocs init
```

Please note that some features may change your existing code, make sure to commit your changes to Git before running it.
6 changes: 6 additions & 0 deletions apps/docs/content/docs/cli/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"root": true,
"title": "Fumadocs CLI",
"description": "The CLI tool for docs automation",
"icon": "Terminal"
}
4 changes: 3 additions & 1 deletion apps/docs/content/docs/headless/meta.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"title": "headless",
"title": "Fumadocs Core",
"description": "The headless library",
"icon": "Library",
"root": true,
"pages": [
"---Guide---",
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/docs/mdx/manifest.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default defineConfig({
```

During a production build (`next build`), Fumadocs MDX will output a manifest file in `.source/manifest.json`.
You can use it to collect build infos.
You can use it to collect build information.

### What is It?

Expand Down
4 changes: 3 additions & 1 deletion apps/docs/content/docs/mdx/meta.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"title": "mdx",
"title": "Fumadocs MDX",
"description": "The official content source",
"icon": "Pencil",
"root": true,
"pages": [
"---Guide---",
Expand Down
3 changes: 3 additions & 0 deletions apps/docs/content/docs/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"pages": ["ui", "headless", "mdx", "cli"]
}
4 changes: 3 additions & 1 deletion apps/docs/content/docs/ui/internationalization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ source.getPage(params.slug, params.lang);
source.getPages(params.lang);
```

See [Source API](/docs/headless/source-api) for other usages.

### Middleware

Create a middleware that redirects users to appropriate locale.
Expand Down Expand Up @@ -117,7 +119,7 @@ Make sure to update references to `source` and configure Static Site Generation

### Writing Documents

see [Page Conventions](/docs/ui/page-conventions#internationalization) to learn how to organize your documents.
see [Page Conventions](/docs/ui/page-conventions#internationalization) to learn how to organize your documents.

### Search

Expand Down
Loading

0 comments on commit 367f4c3

Please sign in to comment.