Core: Support external: to mark links as external in meta.json

This commit is contained in:
Fuma Nama
2025-10-27 19:03:14 +08:00
parent 8d5e9793f5
commit 99971c7bfb
8 changed files with 44 additions and 25 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-core': patch
---
Support `external:` to mark links as external in `meta.json`
@@ -137,16 +137,15 @@ Folder items are sorted alphabetically by default, you can add or control the or
> When specified, items are not included unless they are listed in `pages`.
- **Path**: a path to page or folder, like`./nested/page`.
- **Separator** (`---Label---`): a separator between two sections, use `---[Icon]Label---` to include icons.
- **Link** (`[Text](url)`): insert links, use `[Icon][Text](url)` to include icons.
Special Items:
- **Rest** (`...`): include remaining pages (sorted alphabetically).
- **Reversed Rest** (`z...a`): reversed **Rest** item.
- **Extract** (`...folder`): extract the items from a folder.
- **Except** (`!item`): Exclude an item from `...` or `z...a`.
| Type | Syntax | Description |
| ----------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| **Path** | `./path/to/page` | a path to page or folder. |
| **Separator** | `---Label---`<br/>`---[Icon]Label---` | a separator between two sections (icon supported). |
| **Link** | `[Text](url)`<br/>`[Icon][Text](url)`<br/>`external:[Text](url)` | insert links (icon supported)<br/>add a `external:` prefix to mark links as external. |
| **Rest** | `...` | include remaining pages (sorted alphabetically). |
| **Reversed Rest** | `z...a` | reversed **Rest** item. |
| **Extract** | `...folder` | extract the items from a folder. |
| **Except** | `!item` | Exclude an item from `...` or `z...a`. |
```json title="meta.json"
{
+8 -2
View File
@@ -13,7 +13,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"paths": {
"@/*": ["./*"],
@@ -25,6 +25,12 @@
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": ["node_modules"]
}
@@ -25,6 +25,11 @@ export interface Item {
type: 'page';
name: ReactNode;
url: string;
/**
* Whether the link should be treated as external (e.g. use HTML <a> tag).
*
* When unspecified, it depends on the value of `url`.
*/
external?: boolean;
description?: ReactNode;
@@ -84,7 +84,8 @@ export interface PageTreeBuilder {
}
const group = /^\((?<name>.+)\)$/;
const link = /^(?:\[(?<icon>[^\]]+)])?\[(?<name>[^\]]+)]\((?<url>[^)]+)\)$/;
const link =
/^(?<external>external:)?(?:\[(?<icon>[^\]]+)])?\[(?<name>[^\]]+)]\((?<url>[^)]+)\)$/;
const separator = /^---(?:\[(?<icon>[^\]]+)])?(?<name>.+)---|^---$/;
const rest = '...' as const;
const restReversed = 'z...a' as const;
@@ -148,16 +149,14 @@ function resolveFolderItem(
match = link.exec(item);
if (match?.groups) {
const { icon, url, name } = match.groups;
const isRelative =
url.startsWith('/') || url.startsWith('#') || url.startsWith('.');
const { icon, url, name, external } = match.groups;
let node: PageTree.Item = {
type: 'page',
icon,
name,
url,
external: !isRelative,
external: external ? true : undefined,
};
for (const transformer of ctx.transformers) {
+2 -2
View File
@@ -1,6 +1,6 @@
import { Source, SourceConfig } from '@/source';
import type { Source } from '@/source';
export const source: Source<SourceConfig> = {
export const source: Source = {
files: [
{
type: 'page',
+8 -4
View File
@@ -46,17 +46,21 @@
"type": "folder",
},
{
"external": true,
"name": "Text",
"type": "page",
"url": "https://google.com",
},
{
"icon": "Icon",
"name": "Text",
"type": "page",
"url": "https://google.com",
},
{
"external": true,
"icon": "Icon",
"name": "Text",
"name": "AI",
"type": "page",
"url": "https://google.com",
"url": "/llms-full.txt",
},
],
"fallback": {
+3 -2
View File
@@ -1,6 +1,6 @@
import type { Source, SourceConfig } from '@/source';
import type { Source } from '@/source';
export const source: Source<SourceConfig> = {
export const source: Source = {
files: [
{
type: 'page',
@@ -26,6 +26,7 @@ export const source: Source<SourceConfig> = {
'nested',
'[Text](https://google.com)',
'[Icon][Text](https://google.com)',
'external:[AI](/llms-full.txt)',
],
},
},