diff --git a/content-collections.ts b/content-collections.ts
index d62e1d7..0e51ed3 100644
--- a/content-collections.ts
+++ b/content-collections.ts
@@ -9,6 +9,11 @@ import { createHighlighter } from 'shiki';
import path from "path";
import { LOCALES, DEFAULT_LOCALE } from "@/i18n/routing";
import { visit } from 'unist-util-visit';
+import {
+ createMetaSchema,
+ createDocSchema,
+ transformMDX,
+} from '@fumadocs/content-collections/configuration';
/**
* Content Collections documentation
@@ -17,6 +22,26 @@ import { visit } from 'unist-util-visit';
* 3. https://www.content-collections.dev/docs/transform#join-collections
*/
+/**
+ * Fumadocs documentation
+ * 1. https://fumadocs.com/docs/configuration
+ */
+const docs = defineCollection({
+ name: 'docs',
+ directory: 'content/docs',
+ include: '**/*.mdx',
+ schema: createDocSchema,
+ transform: transformMDX,
+});
+
+const metas = defineCollection({
+ name: 'meta',
+ directory: 'content/docs',
+ include: '**/meta.json',
+ parser: 'json',
+ schema: createMetaSchema,
+});
+
/**
* Blog Author collection
*
@@ -338,5 +363,5 @@ const compileWithCodeCopy = async (
};
export default defineConfig({
- collections: [authors, categories, posts, pages, releases]
+ collections: [docs, metas, authors, categories, posts, pages, releases]
});
\ No newline at end of file
diff --git a/content/docs/index.mdx b/content/docs/index.mdx
new file mode 100644
index 0000000..986a7fa
--- /dev/null
+++ b/content/docs/index.mdx
@@ -0,0 +1,13 @@
+---
+title: Hello World
+description: Your first document
+---
+
+Welcome to the docs! You can start writing documents in `/content/docs`.
+
+## What is Next?
+
+
+
+
+
diff --git a/content/docs/test.mdx b/content/docs/test.mdx
new file mode 100644
index 0000000..d1ee3a8
--- /dev/null
+++ b/content/docs/test.mdx
@@ -0,0 +1,17 @@
+---
+title: Components
+description: Components
+---
+
+## Code Block
+
+```js
+console.log('Hello World');
+```
+
+## Cards
+
+
+
+
+
diff --git a/messages/en.json b/messages/en.json
index a08d7bd..b2b3a0f 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -163,6 +163,9 @@
"blog": {
"title": "Blog"
},
+ "docs": {
+ "title": "Docs"
+ },
"ai": {
"title": "AI Tools",
"items": {
diff --git a/messages/zh.json b/messages/zh.json
index 7ac6da3..687412a 100644
--- a/messages/zh.json
+++ b/messages/zh.json
@@ -158,6 +158,9 @@
"blog": {
"title": "博客"
},
+ "docs": {
+ "title": "文档"
+ },
"ai": {
"title": "AI 工具",
"items": {
diff --git a/package.json b/package.json
index c5ca7e0..c771d22 100644
--- a/package.json
+++ b/package.json
@@ -7,16 +7,21 @@
"build": "content-collections build && next build",
"start": "next start",
"lint": "next lint",
+ "docs": "content-collections build",
"email": "email dev --dir src/mail/emails --port 3333"
},
"dependencies": {
"@ai-sdk/openai": "^1.1.13",
"@aws-sdk/client-s3": "^3.758.0",
"@aws-sdk/s3-request-presigner": "^3.758.0",
+ "@content-collections/core": "^0.8.0",
+ "@content-collections/mdx": "^0.2.0",
+ "@content-collections/next": "^0.2.4",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
+ "@fumadocs/content-collections": "^1.1.8",
"@hookform/resolvers": "^4.1.0",
"@neondatabase/serverless": "^0.10.4",
"@radix-ui/react-accordion": "^1.2.3",
@@ -68,6 +73,8 @@
"drizzle-orm": "^0.39.3",
"embla-carousel-react": "^8.5.2",
"framer-motion": "^12.4.7",
+ "fumadocs-core": "^15.1.2",
+ "fumadocs-ui": "^15.1.2",
"geist": "^1.3.1",
"input-otp": "^1.4.2",
"lucide-react": "^0.483.0",
@@ -110,9 +117,6 @@
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@content-collections/cli": "^0.1.6",
- "@content-collections/core": "^0.8.0",
- "@content-collections/mdx": "^0.2.0",
- "@content-collections/next": "^0.2.4",
"@tailwindcss/postcss": "^4.0.14",
"@types/node": "^20",
"@types/pg": "^8.11.11",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f3a69cd..996b9cf 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,6 +17,15 @@ importers:
'@aws-sdk/s3-request-presigner':
specifier: ^3.758.0
version: 3.758.0
+ '@content-collections/core':
+ specifier: ^0.8.0
+ version: 0.8.0(typescript@5.7.3)
+ '@content-collections/mdx':
+ specifier: ^0.2.0
+ version: 0.2.0(@content-collections/core@0.8.0(typescript@5.7.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@content-collections/next':
+ specifier: ^0.2.4
+ version: 0.2.4(@content-collections/core@0.8.0(typescript@5.7.3))(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
'@dnd-kit/core':
specifier: ^6.3.1
version: 6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -29,6 +38,9 @@ importers:
'@dnd-kit/utilities':
specifier: ^3.2.2
version: 3.2.2(react@19.0.0)
+ '@fumadocs/content-collections':
+ specifier: ^1.1.8
+ version: 1.1.8(@content-collections/core@0.8.0(typescript@5.7.3))(@content-collections/mdx@0.2.0(@content-collections/core@0.8.0(typescript@5.7.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(fumadocs-core@15.1.2(@types/react@19.0.9)(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
'@hookform/resolvers':
specifier: ^4.1.0
version: 4.1.0(react-hook-form@7.54.2(react@19.0.0))
@@ -182,6 +194,12 @@ importers:
framer-motion:
specifier: ^12.4.7
version: 12.4.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ fumadocs-core:
+ specifier: ^15.1.2
+ version: 15.1.2(@types/react@19.0.9)(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ fumadocs-ui:
+ specifier: ^15.1.2
+ version: 15.1.2(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(fumadocs-core@15.1.2(@types/react@19.0.9)(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tailwindcss@4.0.14)
geist:
specifier: ^1.3.1
version: 1.3.1(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
@@ -303,15 +321,6 @@ importers:
'@content-collections/cli':
specifier: ^0.1.6
version: 0.1.6(@content-collections/core@0.8.0(typescript@5.7.3))
- '@content-collections/core':
- specifier: ^0.8.0
- version: 0.8.0(typescript@5.7.3)
- '@content-collections/mdx':
- specifier: ^0.2.0
- version: 0.2.0(@content-collections/core@0.8.0(typescript@5.7.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@content-collections/next':
- specifier: ^0.2.4
- version: 0.2.4(@content-collections/core@0.8.0(typescript@5.7.3))(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
'@tailwindcss/postcss':
specifier: ^4.0.14
version: 4.0.14
@@ -1533,6 +1542,13 @@ packages:
'@formatjs/intl-localematcher@0.6.0':
resolution: {integrity: sha512-4rB4g+3hESy1bHSBG3tDFaMY2CH67iT7yne1e+0CLTsGLDcmoEWWpJjjpWVaYgYfYuohIRuo0E+N536gd2ZHZA==}
+ '@fumadocs/content-collections@1.1.8':
+ resolution: {integrity: sha512-eHXyMw9fnwtn/YkCDbcPTGSqMcydayIK4AHUNbrC4bzMKy+Am2E0bbF9KAadxd6M/99wWtaPBQEECoL3Rt/RNQ==}
+ peerDependencies:
+ '@content-collections/core': 0.x.x
+ '@content-collections/mdx': 0.x.x
+ fumadocs-core: ^14.0.0 || ^15.0.0
+
'@hexagon/base64@1.1.28':
resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==}
@@ -1798,6 +1814,10 @@ packages:
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
+ '@orama/orama@3.1.3':
+ resolution: {integrity: sha512-UdtAMLe2RxtqvmfNDJSMpYoQYUpXgs+9qXVVFCO0BqHF86gp+uz8N6ftkaLe1p55OQXmliciw7BH34GFozKLnQ==}
+ engines: {node: '>= 16.0.0'}
+
'@parcel/watcher-android-arm64@2.5.1':
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
engines: {node: '>= 10.0.0'}
@@ -2652,21 +2672,45 @@ packages:
'@shikijs/core@2.4.2':
resolution: {integrity: sha512-V0kXYB/70xA3CO+b2Pz9kcSThaOUfObOEkGeHsKSFqV6rultaWPfeyZPpBlKHMUXO9Bt1ZGINDCctN90pQvnTg==}
+ '@shikijs/core@3.2.1':
+ resolution: {integrity: sha512-FhsdxMWYu/C11sFisEp7FMGBtX/OSSbnXZDMBhGuUDBNTdsoZlMSgQv5f90rwvzWAdWIW6VobD+G3IrazxA6dQ==}
+
'@shikijs/engine-javascript@2.4.2':
resolution: {integrity: sha512-WRg63Lfta+5RJ0y0/ns1e1NqSxo+jSQclMf9kBHvtchLhR/x3R/E3PSNFiCM+t7oo+d9/VCCp1kURqsSVTHWJg==}
+ '@shikijs/engine-javascript@3.2.1':
+ resolution: {integrity: sha512-eMdcUzN3FMQYxOmRf2rmU8frikzoSHbQDFH2hIuXsrMO+IBOCI9BeeRkCiBkcLDHeRKbOCtYMJK3D6U32ooU9Q==}
+
'@shikijs/engine-oniguruma@2.4.2':
resolution: {integrity: sha512-YmvW7XcvT2f2pf1r1IvKd48fFYcsZRMMISRr2nY1fE2uOF4xcm+84R7+yg4jNAblrFcXU9tDrkllJKH2uD3mBQ==}
+ '@shikijs/engine-oniguruma@3.2.1':
+ resolution: {integrity: sha512-wZZAkayEn6qu2+YjenEoFqj0OyQI64EWsNR6/71d1EkG4sxEOFooowKivsWPpaWNBu3sxAG+zPz5kzBL/SsreQ==}
+
'@shikijs/langs@2.4.2':
resolution: {integrity: sha512-USwSIDIxalwON4FSE2IFMGmAvM250RNdWjOf79zj2JjV2fsNJWn0vvEE9gh1WtvPp2l5BXXhdybFYA6ek7ogFQ==}
+ '@shikijs/langs@3.2.1':
+ resolution: {integrity: sha512-If0iDHYRSGbihiA8+7uRsgb1er1Yj11pwpX1c6HLYnizDsKAw5iaT3JXj5ZpaimXSWky/IhxTm7C6nkiYVym+A==}
+
+ '@shikijs/rehype@3.2.1':
+ resolution: {integrity: sha512-wj4TXI1PQ3TNPyXudUzKfdFIMneTxFym3HKKfWRzbOSAS8P4mECR+ttdUPhYU1dxrXrsatWxTJezOcEjiA0z8g==}
+
'@shikijs/themes@2.4.2':
resolution: {integrity: sha512-W6uxyv91JWI6udgBpsSRCdmIp8WPxOq5Ys9Nj9royB+Or8sYmvnEBHLw6f+dZB9DIlFgvRPw5VnlwUx5ofKMKA==}
+ '@shikijs/themes@3.2.1':
+ resolution: {integrity: sha512-k5DKJUT8IldBvAm8WcrDT5+7GA7se6lLksR+2E3SvyqGTyFMzU2F9Gb7rmD+t+Pga1MKrYFxDIeyWjMZWM6uBQ==}
+
+ '@shikijs/transformers@3.2.1':
+ resolution: {integrity: sha512-oIT40p8LOPV/6XLnUrVPeRtJtbu0Mpl+BjGFuMXw870eX9zTSQlidg7CsksFDVyUiSAOC/CH1RQm+ldZp0/6eQ==}
+
'@shikijs/types@2.4.2':
resolution: {integrity: sha512-e28aFDPwVgK8H2nPrEA5CexLa5yumBvb5aF6nN4SlmqaBFOuGQdxX/Cfh8rwRFALepJtlj0P3wvJ4oL+ndxgSA==}
+ '@shikijs/types@3.2.1':
+ resolution: {integrity: sha512-/NTWAk4KE2M8uac0RhOsIhYQf4pdU0OywQuYDGIGAJ6Mjunxl2cGiuLkvu4HLCMn+OTTLRWkjZITp+aYJv60yA==}
+
'@shikijs/vscode-textmate@10.0.2':
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
@@ -3320,6 +3364,9 @@ packages:
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
engines: {node: '>=16'}
+ compute-scroll-into-view@3.1.1:
+ resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
+
concurrently@9.1.2:
resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==}
engines: {node: '>=18'}
@@ -3347,6 +3394,11 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
+ cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -3788,6 +3840,38 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
+ fumadocs-core@15.1.2:
+ resolution: {integrity: sha512-KbDZ2euvyXQ0M+ch6p4ZlrQzw6MqRBp7Z/2LbQC8fW+FYJUI9zKy/ThS04p2tTiz+6DN1Pi4nIuoOn7F2iCpbQ==}
+ peerDependencies:
+ '@oramacloud/client': 1.x.x || 2.x.x
+ algoliasearch: 4.24.0
+ next: 14.x.x || 15.x.x
+ react: 18.x.x || 19.x.x
+ react-dom: 18.x.x || 19.x.x
+ peerDependenciesMeta:
+ '@oramacloud/client':
+ optional: true
+ algoliasearch:
+ optional: true
+ next:
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+
+ fumadocs-ui@15.1.2:
+ resolution: {integrity: sha512-Jel9zhg85BfMfzDW2YX0lE0qeqnQmWj4s9QpbdKnPnrqeq2jRJJnpJExk3kaeWGG5KousEWG5ihsz3sFQvYCYw==}
+ peerDependencies:
+ fumadocs-core: 15.1.2
+ next: 14.x.x || 15.x.x
+ react: 18.x.x || 19.x.x
+ react-dom: 18.x.x || 19.x.x
+ tailwindcss: ^3.4.14 || ^4.0.0
+ peerDependenciesMeta:
+ tailwindcss:
+ optional: true
+
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@@ -3876,12 +3960,21 @@ packages:
hast-util-to-estree@3.1.1:
resolution: {integrity: sha512-IWtwwmPskfSmma9RpzCappDUitC8t5jhAynHhc1m2+5trOgsrp7txscUSavc5Ic8PATyAjfrCK1wgtxh2cICVQ==}
+ hast-util-to-estree@3.1.3:
+ resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==}
+
hast-util-to-html@9.0.4:
resolution: {integrity: sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==}
+ hast-util-to-html@9.0.5:
+ resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
+
hast-util-to-jsx-runtime@2.3.2:
resolution: {integrity: sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==}
+ hast-util-to-jsx-runtime@2.3.6:
+ resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
+
hast-util-to-string@3.0.1:
resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==}
@@ -3904,6 +3997,11 @@ packages:
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ image-size@2.0.1:
+ resolution: {integrity: sha512-NI6NK/2zchlZopsQrcVIS7jxA0/rtIy74B+/rx5s7rKQyFebmQjZVhzxXgRZJROk+WhhOq+S6sUaODxp0L5hfg==}
+ engines: {node: '>=16.x'}
+ hasBin: true
+
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -4113,6 +4211,9 @@ packages:
lite-emit@2.3.0:
resolution: {integrity: sha512-QMPrnwPho7lfkzZUN3a0RJ/oiwpt464eXf6aVh1HGOYh+s7Utu78q3FcFbW59c8TNWWQaz9flKN1cEb8dmxD+g==}
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@@ -4446,6 +4547,12 @@ packages:
react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ next-themes@0.4.6:
+ resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
+ peerDependencies:
+ react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+
next@15.1.2:
resolution: {integrity: sha512-nLJDV7peNy+0oHlmY2JZjzMfJ8Aj0/dd3jCwSZS8ZiO5nkQfcZRqDrRN3U5rJtqVTQneIOGZzb6LCNrk7trMCQ==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
@@ -4518,9 +4625,15 @@ packages:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'}
+ oniguruma-parser@0.5.4:
+ resolution: {integrity: sha512-yNxcQ8sKvURiTwP0mV6bLQCYE7NKfKRRWunhbZnXgxSmB1OXa1lHrN3o4DZd+0Si0kU5blidK7BcROO8qv5TZA==}
+
oniguruma-to-es@3.1.0:
resolution: {integrity: sha512-BJ3Jy22YlgejHSO7Fvmz1kKazlaPmRSUH+4adTDUS/dKQ4wLxI+gALZ8updbaux7/m7fIlpgOZ5fp/Inq5jUAw==}
+ oniguruma-to-es@4.1.0:
+ resolution: {integrity: sha512-SNwG909cSLo4vPyyPbU/VJkEc9WOXqu2ycBlfd1UCXLqk1IijcQktSBb2yRQ2UFPsDhpkaf+C1dtT3PkLK/yWA==}
+
ora@5.4.1:
resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
engines: {node: '>=10'}
@@ -4618,6 +4731,10 @@ packages:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
+ postcss-selector-parser@7.1.0:
+ resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==}
+ engines: {node: '>=4'}
+
postcss@8.4.31:
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
engines: {node: ^10 || ^12 || >=14}
@@ -4679,6 +4796,9 @@ packages:
property-information@6.5.0:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
+ property-information@7.0.0:
+ resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==}
+
proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
@@ -4724,6 +4844,12 @@ packages:
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+ react-medium-image-zoom@5.2.14:
+ resolution: {integrity: sha512-nfTVYcAUnBzXQpPDcZL+cG/e6UceYUIG+zDcnemL7jtAqbJjVVkA85RgneGtJeni12dTyiRPZVM6Szkmwd/o8w==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
react-promise-suspense@0.3.4:
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
@@ -4908,6 +5034,9 @@ packages:
scheduler@0.25.0:
resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
+ scroll-into-view-if-needed@3.1.0:
+ resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==}
+
section-matter@1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}
@@ -4949,6 +5078,9 @@ packages:
shiki@2.4.2:
resolution: {integrity: sha512-kPOa6plKRlylb23/qOtO+iBI3HYO84IgMix9oc7oet9WcsnuGHCPK4s/v7635nkUSmv+F6s6xmaDreNs5z6v+w==}
+ shiki@3.2.1:
+ resolution: {integrity: sha512-VML/2o1/KGYkEf/stJJ+s9Ypn7jUKQPomGLGYso4JJFMFxVDyPNsjsI3MB3KLjlMOeH44gyaPdXC6rik2WXvUQ==}
+
side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'}
@@ -5062,6 +5194,9 @@ packages:
strnum@1.1.2:
resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==}
+ style-to-js@1.1.16:
+ resolution: {integrity: sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw==}
+
style-to-object@1.0.8:
resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==}
@@ -6601,6 +6736,12 @@ snapshots:
dependencies:
tslib: 2.8.1
+ '@fumadocs/content-collections@1.1.8(@content-collections/core@0.8.0(typescript@5.7.3))(@content-collections/mdx@0.2.0(@content-collections/core@0.8.0(typescript@5.7.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(fumadocs-core@15.1.2(@types/react@19.0.9)(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))':
+ dependencies:
+ '@content-collections/core': 0.8.0(typescript@5.7.3)
+ '@content-collections/mdx': 0.2.0(@content-collections/core@0.8.0(typescript@5.7.3))(acorn@8.14.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ fumadocs-core: 15.1.2(@types/react@19.0.9)(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+
'@hexagon/base64@1.1.28': {}
'@hookform/resolvers@4.1.0(react-hook-form@7.54.2(react@19.0.0))':
@@ -6817,6 +6958,8 @@ snapshots:
'@opentelemetry/api@1.9.0': {}
+ '@orama/orama@3.1.3': {}
+
'@parcel/watcher-android-arm64@2.5.1':
optional: true
@@ -7710,30 +7853,75 @@ snapshots:
'@types/hast': 3.0.4
hast-util-to-html: 9.0.4
+ '@shikijs/core@3.2.1':
+ dependencies:
+ '@shikijs/types': 3.2.1
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+ hast-util-to-html: 9.0.5
+
'@shikijs/engine-javascript@2.4.2':
dependencies:
'@shikijs/types': 2.4.2
'@shikijs/vscode-textmate': 10.0.2
oniguruma-to-es: 3.1.0
+ '@shikijs/engine-javascript@3.2.1':
+ dependencies:
+ '@shikijs/types': 3.2.1
+ '@shikijs/vscode-textmate': 10.0.2
+ oniguruma-to-es: 4.1.0
+
'@shikijs/engine-oniguruma@2.4.2':
dependencies:
'@shikijs/types': 2.4.2
'@shikijs/vscode-textmate': 10.0.2
+ '@shikijs/engine-oniguruma@3.2.1':
+ dependencies:
+ '@shikijs/types': 3.2.1
+ '@shikijs/vscode-textmate': 10.0.2
+
'@shikijs/langs@2.4.2':
dependencies:
'@shikijs/types': 2.4.2
+ '@shikijs/langs@3.2.1':
+ dependencies:
+ '@shikijs/types': 3.2.1
+
+ '@shikijs/rehype@3.2.1':
+ dependencies:
+ '@shikijs/types': 3.2.1
+ '@types/hast': 3.0.4
+ hast-util-to-string: 3.0.1
+ shiki: 3.2.1
+ unified: 11.0.5
+ unist-util-visit: 5.0.0
+
'@shikijs/themes@2.4.2':
dependencies:
'@shikijs/types': 2.4.2
+ '@shikijs/themes@3.2.1':
+ dependencies:
+ '@shikijs/types': 3.2.1
+
+ '@shikijs/transformers@3.2.1':
+ dependencies:
+ '@shikijs/core': 3.2.1
+ '@shikijs/types': 3.2.1
+
'@shikijs/types@2.4.2':
dependencies:
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
+ '@shikijs/types@3.2.1':
+ dependencies:
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
'@shikijs/vscode-textmate@10.0.2': {}
'@simplewebauthn/browser@13.1.0': {}
@@ -8491,6 +8679,8 @@ snapshots:
commander@11.1.0: {}
+ compute-scroll-into-view@3.1.1: {}
+
concurrently@9.1.2:
dependencies:
chalk: 4.1.2
@@ -8523,6 +8713,8 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
+ cssesc@3.0.0: {}
+
csstype@3.1.3: {}
d3-array@3.2.4:
@@ -8971,6 +9163,59 @@ snapshots:
fsevents@2.3.3:
optional: true
+ fumadocs-core@15.1.2(@types/react@19.0.9)(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ dependencies:
+ '@formatjs/intl-localematcher': 0.6.0
+ '@orama/orama': 3.1.3
+ '@shikijs/rehype': 3.2.1
+ '@shikijs/transformers': 3.2.1
+ github-slugger: 2.0.0
+ hast-util-to-estree: 3.1.3
+ hast-util-to-jsx-runtime: 2.3.6
+ image-size: 2.0.1
+ negotiator: 1.0.0
+ react-remove-scroll: 2.6.3(@types/react@19.0.9)(react@19.0.0)
+ remark: 15.0.1
+ remark-gfm: 4.0.1
+ scroll-into-view-if-needed: 3.1.0
+ shiki: 3.2.1
+ unist-util-visit: 5.0.0
+ optionalDependencies:
+ next: 15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+ transitivePeerDependencies:
+ - '@types/react'
+ - supports-color
+
+ fumadocs-ui@15.1.2(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(fumadocs-core@15.1.2(@types/react@19.0.9)(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tailwindcss@4.0.14):
+ dependencies:
+ '@radix-ui/react-accordion': 1.2.3(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-collapsible': 1.1.3(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-dialog': 1.1.6(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-direction': 1.1.0(@types/react@19.0.9)(react@19.0.0)
+ '@radix-ui/react-navigation-menu': 1.2.5(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-popover': 1.1.6(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-scroll-area': 1.2.3(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-slot': 1.1.2(@types/react@19.0.9)(react@19.0.0)
+ '@radix-ui/react-tabs': 1.1.3(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ class-variance-authority: 0.7.1
+ fumadocs-core: 15.1.2(@types/react@19.0.9)(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ lodash.merge: 4.6.2
+ lucide-react: 0.483.0(react@19.0.0)
+ next: 15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ next-themes: 0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ postcss-selector-parser: 7.1.0
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+ react-medium-image-zoom: 5.2.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ tailwind-merge: 3.0.2
+ optionalDependencies:
+ tailwindcss: 4.0.14
+ transitivePeerDependencies:
+ - '@types/react'
+ - '@types/react-dom'
+
function-bind@1.1.2: {}
geist@1.3.1(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)):
@@ -9098,6 +9343,27 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ hast-util-to-estree@3.1.3:
+ dependencies:
+ '@types/estree': 1.0.6
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ comma-separated-tokens: 2.0.3
+ devlop: 1.1.0
+ estree-util-attach-comments: 3.0.0
+ estree-util-is-identifier-name: 3.0.0
+ hast-util-whitespace: 3.0.0
+ mdast-util-mdx-expression: 2.0.1
+ mdast-util-mdx-jsx: 3.2.0
+ mdast-util-mdxjs-esm: 2.0.1
+ property-information: 7.0.0
+ space-separated-tokens: 2.0.2
+ style-to-js: 1.1.16
+ unist-util-position: 5.0.0
+ zwitch: 2.0.4
+ transitivePeerDependencies:
+ - supports-color
+
hast-util-to-html@9.0.4:
dependencies:
'@types/hast': 3.0.4
@@ -9112,6 +9378,20 @@ snapshots:
stringify-entities: 4.0.4
zwitch: 2.0.4
+ hast-util-to-html@9.0.5:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ ccount: 2.0.1
+ comma-separated-tokens: 2.0.3
+ hast-util-whitespace: 3.0.0
+ html-void-elements: 3.0.0
+ mdast-util-to-hast: 13.2.0
+ property-information: 7.0.0
+ space-separated-tokens: 2.0.2
+ stringify-entities: 4.0.4
+ zwitch: 2.0.4
+
hast-util-to-jsx-runtime@2.3.2:
dependencies:
'@types/estree': 1.0.6
@@ -9132,6 +9412,26 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ hast-util-to-jsx-runtime@2.3.6:
+ dependencies:
+ '@types/estree': 1.0.6
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ comma-separated-tokens: 2.0.3
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ hast-util-whitespace: 3.0.0
+ mdast-util-mdx-expression: 2.0.1
+ mdast-util-mdx-jsx: 3.2.0
+ mdast-util-mdxjs-esm: 2.0.1
+ property-information: 7.0.0
+ space-separated-tokens: 2.0.2
+ style-to-js: 1.1.16
+ unist-util-position: 5.0.0
+ vfile-message: 4.0.2
+ transitivePeerDependencies:
+ - supports-color
+
hast-util-to-string@3.0.1:
dependencies:
'@types/hast': 3.0.4
@@ -9167,6 +9467,8 @@ snapshots:
ieee754@1.2.1: {}
+ image-size@2.0.1: {}
+
inherits@2.0.4: {}
ini@1.3.8: {}
@@ -9327,6 +9629,8 @@ snapshots:
lite-emit@2.3.0: {}
+ lodash.merge@4.6.2: {}
+
lodash@4.17.21: {}
log-symbols@4.1.0:
@@ -9916,6 +10220,11 @@ snapshots:
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
+ next-themes@0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ dependencies:
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+
next@15.1.2(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@next/env': 15.1.2
@@ -9988,12 +10297,21 @@ snapshots:
dependencies:
mimic-fn: 2.1.0
+ oniguruma-parser@0.5.4: {}
+
oniguruma-to-es@3.1.0:
dependencies:
emoji-regex-xs: 1.0.0
regex: 6.0.1
regex-recursion: 6.0.2
+ oniguruma-to-es@4.1.0:
+ dependencies:
+ emoji-regex-xs: 1.0.0
+ oniguruma-parser: 0.5.4
+ regex: 6.0.1
+ regex-recursion: 6.0.2
+
ora@5.4.1:
dependencies:
bl: 4.1.0
@@ -10106,6 +10424,11 @@ snapshots:
pluralize@8.0.0: {}
+ postcss-selector-parser@7.1.0:
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
postcss@8.4.31:
dependencies:
nanoid: 3.3.8
@@ -10161,6 +10484,8 @@ snapshots:
property-information@6.5.0: {}
+ property-information@7.0.0: {}
+
proto-list@1.2.4: {}
pvtsutils@1.3.6:
@@ -10225,6 +10550,11 @@ snapshots:
react-is@18.3.1: {}
+ react-medium-image-zoom@5.2.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ dependencies:
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+
react-promise-suspense@0.3.4:
dependencies:
fast-deep-equal: 2.0.1
@@ -10500,6 +10830,10 @@ snapshots:
scheduler@0.25.0: {}
+ scroll-into-view-if-needed@3.1.0:
+ dependencies:
+ compute-scroll-into-view: 3.1.1
+
section-matter@1.0.0:
dependencies:
extend-shallow: 2.0.1
@@ -10565,6 +10899,17 @@ snapshots:
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
+ shiki@3.2.1:
+ dependencies:
+ '@shikijs/core': 3.2.1
+ '@shikijs/engine-javascript': 3.2.1
+ '@shikijs/engine-oniguruma': 3.2.1
+ '@shikijs/langs': 3.2.1
+ '@shikijs/themes': 3.2.1
+ '@shikijs/types': 3.2.1
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
@@ -10705,6 +11050,10 @@ snapshots:
strnum@1.1.2: {}
+ style-to-js@1.1.16:
+ dependencies:
+ style-to-object: 1.0.8
+
style-to-object@1.0.8:
dependencies:
inline-style-parser: 0.2.4
diff --git a/src/app/api/search/route.ts b/src/app/api/search/route.ts
new file mode 100644
index 0000000..df88962
--- /dev/null
+++ b/src/app/api/search/route.ts
@@ -0,0 +1,4 @@
+import { source } from '@/lib/source';
+import { createFromSource } from 'fumadocs-core/search/server';
+
+export const { GET } = createFromSource(source);
diff --git a/src/app/docs/[[...slug]]/page.tsx b/src/app/docs/[[...slug]]/page.tsx
new file mode 100644
index 0000000..2f35b04
--- /dev/null
+++ b/src/app/docs/[[...slug]]/page.tsx
@@ -0,0 +1,54 @@
+import { source } from '@/lib/source';
+import { MDXContent } from '@content-collections/mdx/react';
+import defaultMdxComponents, { createRelativeLink } from 'fumadocs-ui/mdx';
+import {
+ DocsBody,
+ DocsDescription,
+ DocsPage,
+ DocsTitle,
+} from 'fumadocs-ui/page';
+import type { Metadata } from 'next';
+import { notFound } from 'next/navigation';
+
+export default async function Page(props: {
+ params: Promise<{ slug?: string[] }>;
+}) {
+ const params = await props.params;
+ const page = source.getPage(params.slug);
+ if (!page) notFound();
+
+ return (
+
+ {page.data.title}
+ {page.data.description}
+
+
+
+
+ );
+}
+
+export function generateStaticParams() {
+ return source.generateParams();
+}
+
+export async function generateMetadata(props: {
+ params: Promise<{ slug?: string[] }>;
+}) {
+ const params = await props.params;
+ const page = source.getPage(params.slug);
+ if (!page) notFound();
+
+ return {
+ title: page.data.title,
+ description: page.data.description,
+ } satisfies Metadata;
+}
diff --git a/src/app/docs/layout.config.tsx b/src/app/docs/layout.config.tsx
new file mode 100644
index 0000000..76b67a2
--- /dev/null
+++ b/src/app/docs/layout.config.tsx
@@ -0,0 +1,34 @@
+import { defaultMessages } from '@/i18n/messages';
+import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
+
+/**
+ * Shared layout configurations
+ *
+ * you can customise layouts individually from:
+ * Home Layout: app/(home)/layout.tsx
+ * Docs Layout: app/docs/layout.tsx
+ */
+export const baseOptions: BaseLayoutProps = {
+ nav: {
+ title: (
+ <>
+
+ {defaultMessages.Metadata.name}
+ >
+ ),
+ },
+ links: [
+ {
+ text: 'Documentation',
+ url: '/docs',
+ active: 'nested-url',
+ },
+ ],
+};
diff --git a/src/app/docs/layout.tsx b/src/app/docs/layout.tsx
new file mode 100644
index 0000000..9696860
--- /dev/null
+++ b/src/app/docs/layout.tsx
@@ -0,0 +1,22 @@
+import { baseOptions } from '@/app/docs/layout.config';
+import { source } from '@/lib/source';
+import { DocsLayout } from 'fumadocs-ui/layouts/docs';
+import { RootProvider } from 'fumadocs-ui/provider';
+import type { ReactNode } from 'react';
+import { fontDMSans } from '@/assets/fonts';
+
+import '@/styles/docs.css';
+
+export default function Layout({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
diff --git a/src/app/manifest.ts b/src/app/manifest.ts
index 40bb61d..78b5c16 100644
--- a/src/app/manifest.ts
+++ b/src/app/manifest.ts
@@ -4,7 +4,7 @@ import { type MetadataRoute } from 'next';
/**
* Generates the Web App Manifest for the application
*
- * generated file name: site.webmanifest
+ * generated file name: manifest.webmanifest
*
* ref: https://github.com/amannn/next-intl/blob/main/examples/example-app-router/src/app/manifest.ts
*
diff --git a/src/config.tsx b/src/config.tsx
index 5a34ce2..22c87fd 100644
--- a/src/config.tsx
+++ b/src/config.tsx
@@ -95,6 +95,11 @@ export function getMenuLinks(): NestedMenuItem[] {
href: Routes.Blog,
external: false,
},
+ {
+ title: t('Marketing.navbar.docs.title'),
+ href: Routes.Docs,
+ external: false,
+ },
{
title: t('Marketing.navbar.ai.title'),
items: [
diff --git a/src/lib/source.ts b/src/lib/source.ts
new file mode 100644
index 0000000..001189e
--- /dev/null
+++ b/src/lib/source.ts
@@ -0,0 +1,8 @@
+import { allDocs, allMetas } from 'content-collections';
+import { loader } from 'fumadocs-core/source';
+import { createMDXSource } from '@fumadocs/content-collections';
+
+export const source = loader({
+ baseUrl: '/docs',
+ source: createMDXSource(allDocs, allMetas),
+});
diff --git a/src/middleware.ts b/src/middleware.ts
index 4d811c5..dd9bdce 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -23,6 +23,6 @@ export const config = {
// (e.g. `/pathnames` -> `/zh/pathnames`)
// Exclude API routes and other Next.js internal routes
// if not exclude api routes, auth routes will not work
- '/((?!api|_next|_vercel|.*\\..*).*)',
+ '/((?!api|_next|_vercel|docs|.*\\..*).*)',
],
};
diff --git a/src/routes.ts b/src/routes.ts
index 342357d..1a1a767 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -14,6 +14,7 @@ export enum Routes {
CookiePolicy = '/cookie-policy',
Blog = '/blog',
+ Docs = '/docs',
Changelog = '/changelog',
Roadmap = 'https://mksaas.featurebase.app',
diff --git a/src/styles/docs.css b/src/styles/docs.css
new file mode 100644
index 0000000..54e28c2
--- /dev/null
+++ b/src/styles/docs.css
@@ -0,0 +1,5 @@
+@import 'tailwindcss';
+@import 'fumadocs-ui/css/neutral.css';
+@import 'fumadocs-ui/css/preset.css';
+
+@source '../../node_modules/fumadocs-ui/dist/**/*.js';