diff --git a/.changeset/poor-rivers-develop.md b/.changeset/poor-rivers-develop.md new file mode 100644 index 0000000000..a737abfa8c --- /dev/null +++ b/.changeset/poor-rivers-develop.md @@ -0,0 +1,6 @@ +--- +'nextra': patch +'nextra-theme-docs': patch +--- + +rename `meta.json` to `_meta.json` diff --git a/.changeset/proud-phones-dress.md b/.changeset/proud-phones-dress.md new file mode 100644 index 0000000000..9e006d7696 --- /dev/null +++ b/.changeset/proud-phones-dress.md @@ -0,0 +1,5 @@ +--- +'nextra-theme-docs': patch +--- + +clicking on folder should navigate to first children if `index` page doesn't exist diff --git a/.changeset/tall-cows-whisper.md b/.changeset/tall-cows-whisper.md new file mode 100644 index 0000000000..57f09397a5 --- /dev/null +++ b/.changeset/tall-cows-whisper.md @@ -0,0 +1,7 @@ +--- +'nextra': patch +'nextra-theme-blog': patch +'nextra-theme-docs': patch +--- + +rename `PageOpts.meta` to `PageOpts.frontMatter` diff --git a/examples/docs/src/pages/meta.json b/examples/docs/src/pages/_meta.json similarity index 100% rename from examples/docs/src/pages/meta.json rename to examples/docs/src/pages/_meta.json diff --git a/examples/docs/src/pages/advanced/meta.json b/examples/docs/src/pages/advanced/_meta.json similarity index 100% rename from examples/docs/src/pages/advanced/meta.json rename to examples/docs/src/pages/advanced/_meta.json diff --git a/examples/docs/src/pages/features/meta.json b/examples/docs/src/pages/features/_meta.json similarity index 100% rename from examples/docs/src/pages/features/meta.json rename to examples/docs/src/pages/features/_meta.json diff --git a/examples/docs/src/pages/themes/meta.json b/examples/docs/src/pages/themes/_meta.json similarity index 100% rename from examples/docs/src/pages/themes/meta.json rename to examples/docs/src/pages/themes/_meta.json diff --git a/examples/docs/src/pages/themes/blog/meta.json b/examples/docs/src/pages/themes/blog/_meta.json similarity index 100% rename from examples/docs/src/pages/themes/blog/meta.json rename to examples/docs/src/pages/themes/blog/_meta.json diff --git a/examples/docs/src/pages/themes/docs/meta.json b/examples/docs/src/pages/themes/docs/_meta.json similarity index 100% rename from examples/docs/src/pages/themes/docs/meta.json rename to examples/docs/src/pages/themes/docs/_meta.json diff --git a/examples/swr-site/pages/meta.en-US.json b/examples/swr-site/pages/_meta.en-US.json similarity index 100% rename from examples/swr-site/pages/meta.en-US.json rename to examples/swr-site/pages/_meta.en-US.json diff --git a/examples/swr-site/pages/meta.es-ES.json b/examples/swr-site/pages/_meta.es-ES.json similarity index 100% rename from examples/swr-site/pages/meta.es-ES.json rename to examples/swr-site/pages/_meta.es-ES.json diff --git a/examples/swr-site/pages/meta.ja.json b/examples/swr-site/pages/_meta.ja.json similarity index 100% rename from examples/swr-site/pages/meta.ja.json rename to examples/swr-site/pages/_meta.ja.json diff --git a/examples/swr-site/pages/meta.ko.json b/examples/swr-site/pages/_meta.ko.json similarity index 100% rename from examples/swr-site/pages/meta.ko.json rename to examples/swr-site/pages/_meta.ko.json diff --git a/examples/swr-site/pages/meta.ru.json b/examples/swr-site/pages/_meta.ru.json similarity index 100% rename from examples/swr-site/pages/meta.ru.json rename to examples/swr-site/pages/_meta.ru.json diff --git a/examples/swr-site/pages/meta.zh-CN.json b/examples/swr-site/pages/_meta.zh-CN.json similarity index 100% rename from examples/swr-site/pages/meta.zh-CN.json rename to examples/swr-site/pages/_meta.zh-CN.json diff --git a/examples/swr-site/pages/about/meta.en-US.json b/examples/swr-site/pages/about/_meta.en-US.json similarity index 100% rename from examples/swr-site/pages/about/meta.en-US.json rename to examples/swr-site/pages/about/_meta.en-US.json diff --git a/examples/swr-site/pages/blog/meta.en-US.json b/examples/swr-site/pages/blog/_meta.en-US.json similarity index 100% rename from examples/swr-site/pages/blog/meta.en-US.json rename to examples/swr-site/pages/blog/_meta.en-US.json diff --git a/examples/swr-site/pages/blog/meta.es-ES.json b/examples/swr-site/pages/blog/_meta.es-ES.json similarity index 100% rename from examples/swr-site/pages/blog/meta.es-ES.json rename to examples/swr-site/pages/blog/_meta.es-ES.json diff --git a/examples/swr-site/pages/blog/meta.ja.json b/examples/swr-site/pages/blog/_meta.ja.json similarity index 100% rename from examples/swr-site/pages/blog/meta.ja.json rename to examples/swr-site/pages/blog/_meta.ja.json diff --git a/examples/swr-site/pages/blog/meta.ko.json b/examples/swr-site/pages/blog/_meta.ko.json similarity index 100% rename from examples/swr-site/pages/blog/meta.ko.json rename to examples/swr-site/pages/blog/_meta.ko.json diff --git a/examples/swr-site/pages/blog/meta.ru.json b/examples/swr-site/pages/blog/_meta.ru.json similarity index 100% rename from examples/swr-site/pages/blog/meta.ru.json rename to examples/swr-site/pages/blog/_meta.ru.json diff --git a/examples/swr-site/pages/blog/meta.zh-CN.json b/examples/swr-site/pages/blog/_meta.zh-CN.json similarity index 100% rename from examples/swr-site/pages/blog/meta.zh-CN.json rename to examples/swr-site/pages/blog/_meta.zh-CN.json diff --git a/examples/swr-site/pages/docs/meta.en-US.json b/examples/swr-site/pages/docs/_meta.en-US.json similarity index 100% rename from examples/swr-site/pages/docs/meta.en-US.json rename to examples/swr-site/pages/docs/_meta.en-US.json diff --git a/examples/swr-site/pages/docs/meta.es-ES.json b/examples/swr-site/pages/docs/_meta.es-ES.json similarity index 100% rename from examples/swr-site/pages/docs/meta.es-ES.json rename to examples/swr-site/pages/docs/_meta.es-ES.json diff --git a/examples/swr-site/pages/docs/meta.ja.json b/examples/swr-site/pages/docs/_meta.ja.json similarity index 100% rename from examples/swr-site/pages/docs/meta.ja.json rename to examples/swr-site/pages/docs/_meta.ja.json diff --git a/examples/swr-site/pages/docs/meta.ko.json b/examples/swr-site/pages/docs/_meta.ko.json similarity index 100% rename from examples/swr-site/pages/docs/meta.ko.json rename to examples/swr-site/pages/docs/_meta.ko.json diff --git a/examples/swr-site/pages/docs/meta.ru.json b/examples/swr-site/pages/docs/_meta.ru.json similarity index 100% rename from examples/swr-site/pages/docs/meta.ru.json rename to examples/swr-site/pages/docs/_meta.ru.json diff --git a/examples/swr-site/pages/docs/meta.zh-CN.json b/examples/swr-site/pages/docs/_meta.zh-CN.json similarity index 100% rename from examples/swr-site/pages/docs/meta.zh-CN.json rename to examples/swr-site/pages/docs/_meta.zh-CN.json diff --git a/examples/swr-site/pages/docs/advanced/meta.en-US.json b/examples/swr-site/pages/docs/advanced/_meta.en-US.json similarity index 100% rename from examples/swr-site/pages/docs/advanced/meta.en-US.json rename to examples/swr-site/pages/docs/advanced/_meta.en-US.json diff --git a/examples/swr-site/pages/docs/advanced/meta.es-ES.json b/examples/swr-site/pages/docs/advanced/_meta.es-ES.json similarity index 100% rename from examples/swr-site/pages/docs/advanced/meta.es-ES.json rename to examples/swr-site/pages/docs/advanced/_meta.es-ES.json diff --git a/examples/swr-site/pages/docs/advanced/meta.ja.json b/examples/swr-site/pages/docs/advanced/_meta.ja.json similarity index 100% rename from examples/swr-site/pages/docs/advanced/meta.ja.json rename to examples/swr-site/pages/docs/advanced/_meta.ja.json diff --git a/examples/swr-site/pages/docs/advanced/meta.ko.json b/examples/swr-site/pages/docs/advanced/_meta.ko.json similarity index 100% rename from examples/swr-site/pages/docs/advanced/meta.ko.json rename to examples/swr-site/pages/docs/advanced/_meta.ko.json diff --git a/examples/swr-site/pages/docs/advanced/meta.ru.json b/examples/swr-site/pages/docs/advanced/_meta.ru.json similarity index 100% rename from examples/swr-site/pages/docs/advanced/meta.ru.json rename to examples/swr-site/pages/docs/advanced/_meta.ru.json diff --git a/examples/swr-site/pages/docs/advanced/meta.zh-CN.json b/examples/swr-site/pages/docs/advanced/_meta.zh-CN.json similarity index 100% rename from examples/swr-site/pages/docs/advanced/meta.zh-CN.json rename to examples/swr-site/pages/docs/advanced/_meta.zh-CN.json diff --git a/examples/swr-site/pages/examples/meta.en-US.json b/examples/swr-site/pages/examples/_meta.en-US.json similarity index 100% rename from examples/swr-site/pages/examples/meta.en-US.json rename to examples/swr-site/pages/examples/_meta.en-US.json diff --git a/examples/swr-site/pages/examples/meta.es-ES.json b/examples/swr-site/pages/examples/_meta.es-ES.json similarity index 100% rename from examples/swr-site/pages/examples/meta.es-ES.json rename to examples/swr-site/pages/examples/_meta.es-ES.json diff --git a/examples/swr-site/pages/examples/meta.ja.json b/examples/swr-site/pages/examples/_meta.ja.json similarity index 100% rename from examples/swr-site/pages/examples/meta.ja.json rename to examples/swr-site/pages/examples/_meta.ja.json diff --git a/examples/swr-site/pages/examples/meta.ko.json b/examples/swr-site/pages/examples/_meta.ko.json similarity index 100% rename from examples/swr-site/pages/examples/meta.ko.json rename to examples/swr-site/pages/examples/_meta.ko.json diff --git a/examples/swr-site/pages/examples/meta.ru.json b/examples/swr-site/pages/examples/_meta.ru.json similarity index 100% rename from examples/swr-site/pages/examples/meta.ru.json rename to examples/swr-site/pages/examples/_meta.ru.json diff --git a/examples/swr-site/pages/examples/meta.zh-CN.json b/examples/swr-site/pages/examples/_meta.zh-CN.json similarity index 100% rename from examples/swr-site/pages/examples/meta.zh-CN.json rename to examples/swr-site/pages/examples/_meta.zh-CN.json diff --git a/examples/swr-site/theme.config.tsx b/examples/swr-site/theme.config.tsx index 4308cf361e..01c9c939f4 100644 --- a/examples/swr-site/theme.config.tsx +++ b/examples/swr-site/theme.config.tsx @@ -131,10 +131,10 @@ const config: DocsThemeConfig = { head() { const config = useConfig(); const description = - config.meta.description || + config.frontMatter.description || "SWR is a React Hooks library for data fetching. SWR first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again."; const image = - config.meta.image || + config.frontMatter.image || "https://assets.vercel.com/image/upload/v1572282926/swr/twitter-card.jpg"; return ( <> diff --git a/packages/nextra-theme-blog/__test__/__fixture__/pageMap.ts b/packages/nextra-theme-blog/__test__/__fixture__/pageMap.ts index ec8a5d48f3..1fae0758e8 100644 --- a/packages/nextra-theme-blog/__test__/__fixture__/pageMap.ts +++ b/packages/nextra-theme-blog/__test__/__fixture__/pageMap.ts @@ -2,7 +2,7 @@ import { BlogPageOpts } from '../../src/types' export const indexOpts: BlogPageOpts = { filePath: 'index.mdx', route: '/', - meta: { + frontMatter: { type: 'page', title: 'About', date: '2020-01-01T00:00:00.000Z' @@ -105,7 +105,7 @@ export const indexOpts: BlogPageOpts = { export const postsOpts: BlogPageOpts = { filePath: 'index.md', route: '/posts', - meta: { + frontMatter: { type: 'posts', title: 'Random Thoughts', date: '2020-01-03T00:00:00.000Z' @@ -208,7 +208,7 @@ export const postsOpts: BlogPageOpts = { export const articleOpts: BlogPageOpts = { filePath: 'aaron-swartz-a-programmable-web.mdx', route: '/posts/aaron-swartz-a-programmable-web', - meta: { + frontMatter: { title: 'Notes on A Programmable Web by Aaron Swartz', date: '2016/5/21', description: diff --git a/packages/nextra-theme-blog/src/article-layout.tsx b/packages/nextra-theme-blog/src/article-layout.tsx index 881bf9de7a..66c267c4c1 100644 --- a/packages/nextra-theme-blog/src/article-layout.tsx +++ b/packages/nextra-theme-blog/src/article-layout.tsx @@ -10,7 +10,7 @@ export const ArticleLayout = ({ children }: { children: ReactNode }) => { const { back } = getParent({ opts, config }) return ( - + {children} {config.postFooter} diff --git a/packages/nextra-theme-blog/src/basic-layout.tsx b/packages/nextra-theme-blog/src/basic-layout.tsx index 317ce6710b..35ce18e32e 100644 --- a/packages/nextra-theme-blog/src/basic-layout.tsx +++ b/packages/nextra-theme-blog/src/basic-layout.tsx @@ -11,7 +11,7 @@ export const BasicLayout = ({ children }: { children: ReactNode }) => {
{title} - {config.head?.({ title, meta: opts.meta })} + {config.head?.({ title, meta: opts.frontMatter })} {opts.hasJsxInH1 ?

: null} diff --git a/packages/nextra-theme-blog/src/blog-context.tsx b/packages/nextra-theme-blog/src/blog-context.tsx index d9a0c876f1..2623ff77fe 100644 --- a/packages/nextra-theme-blog/src/blog-context.tsx +++ b/packages/nextra-theme-blog/src/blog-context.tsx @@ -14,7 +14,7 @@ export const BlogProvider = ({ children, opts }: LayoutProps & { children: ReactNode }): ReactElement => { - const { date } = opts.meta + const { date } = opts.frontMatter if (date && !isValidDate(date)) { throw new Error( diff --git a/packages/nextra-theme-blog/src/index.tsx b/packages/nextra-theme-blog/src/index.tsx index 2edca5662d..5585ee5a49 100644 --- a/packages/nextra-theme-blog/src/index.tsx +++ b/packages/nextra-theme-blog/src/index.tsx @@ -21,7 +21,7 @@ const BlogLayout = ({ children, opts }: LayoutProps & { children: ReactNode }): ReactElement => { - const type = opts.meta.type || 'post' + const type = opts.frontMatter.type || 'post' const Layout = layoutMap[type] if (!Layout) { throw new Error( diff --git a/packages/nextra-theme-blog/src/posts-layout.tsx b/packages/nextra-theme-blog/src/posts-layout.tsx index c869c996b6..486a42821f 100644 --- a/packages/nextra-theme-blog/src/posts-layout.tsx +++ b/packages/nextra-theme-blog/src/posts-layout.tsx @@ -12,9 +12,7 @@ export const PostsLayout = ({ children }: { children: ReactNode }) => { const { config, opts } = useBlogContext() const { posts } = collectPostsAndNavs({ config, opts }) const router = useRouter() - const { - meta: { type } - } = opts + const { type } = opts.frontMatter const tagName = type === 'tag' ? router.query.tag : null const postList = posts.map(post => { if (tagName) { diff --git a/packages/nextra-theme-blog/src/types.ts b/packages/nextra-theme-blog/src/types.ts index ca20cc3807..f8b45da5f0 100644 --- a/packages/nextra-theme-blog/src/types.ts +++ b/packages/nextra-theme-blog/src/types.ts @@ -28,7 +28,7 @@ export interface NextraBlogTheme { } export interface BlogPageOpts extends PageOpts { - meta: Meta + frontMatter: Meta } type Meta = { diff --git a/packages/nextra-theme-docs/__test__/__fixture__/pageMap.ts b/packages/nextra-theme-docs/__test__/__fixture__/pageMap.ts index a1c498f67b..aee529b325 100644 --- a/packages/nextra-theme-docs/__test__/__fixture__/pageMap.ts +++ b/packages/nextra-theme-docs/__test__/__fixture__/pageMap.ts @@ -3,42 +3,42 @@ export const cnPageMap: any[] = [ name: 'blog', children: [ { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'Announcing SWR 1.0' }, locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'Announcing SWR 1.0' }, locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'SWR 1.0 の発表' }, locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'Announcing SWR 1.0' }, locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'Представляем SWR 1.0' }, locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'SWR 1.0 发布' }, @@ -70,7 +70,7 @@ export const cnPageMap: any[] = [ locale: 'zh-CN' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: 'Cache', performance: 'Performance', @@ -79,7 +79,7 @@ export const cnPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: 'Cache', performance: 'Rendimiento', @@ -88,7 +88,7 @@ export const cnPageMap: any[] = [ locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: 'キャッシュ', performance: 'パフォーマンス', @@ -97,7 +97,7 @@ export const cnPageMap: any[] = [ locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: '캐시', performance: '성능', @@ -106,7 +106,7 @@ export const cnPageMap: any[] = [ locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: 'Кеш', performance: 'Производительность', @@ -115,7 +115,7 @@ export const cnPageMap: any[] = [ locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: '缓存', performance: '性能', @@ -172,7 +172,7 @@ export const cnPageMap: any[] = [ locale: 'zh-CN' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': 'Getting Started', options: 'Options', @@ -195,7 +195,7 @@ export const cnPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': 'Comienza', options: 'Opciones', @@ -218,7 +218,7 @@ export const cnPageMap: any[] = [ locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': 'はじめに', options: 'オプション', @@ -241,7 +241,7 @@ export const cnPageMap: any[] = [ locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': '시작하기', options: '옵션', @@ -264,7 +264,7 @@ export const cnPageMap: any[] = [ locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': 'Начало работы', options: 'Опции', @@ -287,7 +287,7 @@ export const cnPageMap: any[] = [ locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': '入门', options: '选项', @@ -397,7 +397,7 @@ export const cnPageMap: any[] = [ locale: 'zh-CN' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: 'Basic Usage', auth: 'Authentication', @@ -408,7 +408,7 @@ export const cnPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: 'Uso Básico', auth: 'Autenticación', @@ -419,7 +419,7 @@ export const cnPageMap: any[] = [ locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: '基本的な使用法', auth: '認証', @@ -430,7 +430,7 @@ export const cnPageMap: any[] = [ locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: '기본 사용법', auth: '인증', @@ -441,7 +441,7 @@ export const cnPageMap: any[] = [ locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: 'Основное использование', auth: 'Аутентификация', @@ -452,7 +452,7 @@ export const cnPageMap: any[] = [ locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: '基本用法', auth: '身份验证', @@ -483,7 +483,7 @@ export const cnPageMap: any[] = [ locale: 'zh-CN' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: 'Introduction', @@ -506,7 +506,7 @@ export const cnPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: 'Introducción', @@ -529,7 +529,7 @@ export const cnPageMap: any[] = [ locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: '前書き', @@ -552,7 +552,7 @@ export const cnPageMap: any[] = [ locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: '소개', @@ -575,7 +575,7 @@ export const cnPageMap: any[] = [ locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: 'Введение', @@ -598,7 +598,7 @@ export const cnPageMap: any[] = [ locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: '简介', @@ -627,42 +627,42 @@ export const usPageMap: any[] = [ name: 'blog', children: [ { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'Announcing SWR 1.0' }, locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'Announcing SWR 1.0' }, locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'SWR 1.0 の発表' }, locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'Announcing SWR 1.0' }, locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'Представляем SWR 1.0' }, locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'swr-v1': 'SWR 1.0 发布' }, @@ -694,7 +694,7 @@ export const usPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: 'Cache', performance: 'Performance', @@ -703,7 +703,7 @@ export const usPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: 'Cache', performance: 'Rendimiento', @@ -712,7 +712,7 @@ export const usPageMap: any[] = [ locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: 'キャッシュ', performance: 'パフォーマンス', @@ -721,7 +721,7 @@ export const usPageMap: any[] = [ locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: '캐시', performance: '성능', @@ -730,7 +730,7 @@ export const usPageMap: any[] = [ locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: 'Кеш', performance: 'Производительность', @@ -739,7 +739,7 @@ export const usPageMap: any[] = [ locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { cache: '缓存', performance: '性能', @@ -796,7 +796,7 @@ export const usPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': 'Getting Started', options: 'Options', @@ -819,7 +819,7 @@ export const usPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': 'Comienza', options: 'Opciones', @@ -842,7 +842,7 @@ export const usPageMap: any[] = [ locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': 'はじめに', options: 'オプション', @@ -865,7 +865,7 @@ export const usPageMap: any[] = [ locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': '시작하기', options: '옵션', @@ -888,7 +888,7 @@ export const usPageMap: any[] = [ locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': 'Начало работы', options: 'Опции', @@ -911,7 +911,7 @@ export const usPageMap: any[] = [ locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { 'getting-started': '入门', options: '选项', @@ -1021,7 +1021,7 @@ export const usPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: 'Basic Usage', auth: 'Authentication', @@ -1032,7 +1032,7 @@ export const usPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: 'Uso Básico', auth: 'Autenticación', @@ -1043,7 +1043,7 @@ export const usPageMap: any[] = [ locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: '基本的な使用法', auth: '認証', @@ -1054,7 +1054,7 @@ export const usPageMap: any[] = [ locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: '기본 사용법', auth: '인증', @@ -1065,7 +1065,7 @@ export const usPageMap: any[] = [ locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: 'Основное использование', auth: 'Аутентификация', @@ -1076,7 +1076,7 @@ export const usPageMap: any[] = [ locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { basic: '基本用法', auth: '身份验证', @@ -1107,7 +1107,7 @@ export const usPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: 'Introduction', @@ -1130,7 +1130,7 @@ export const usPageMap: any[] = [ locale: 'en-US' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: 'Introducción', @@ -1153,7 +1153,7 @@ export const usPageMap: any[] = [ locale: 'es-ES' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: '前書き', @@ -1176,7 +1176,7 @@ export const usPageMap: any[] = [ locale: 'ja' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: '소개', @@ -1199,7 +1199,7 @@ export const usPageMap: any[] = [ locale: 'ko' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: 'Введение', @@ -1222,7 +1222,7 @@ export const usPageMap: any[] = [ locale: 'ru' }, { - name: 'meta.json', + name: '_meta.json', meta: { index: { title: '简介', diff --git a/packages/nextra-theme-docs/__test__/normalize-page.spec.ts b/packages/nextra-theme-docs/__test__/normalize-page.spec.ts index 0136ba7362..f8d96553ff 100644 --- a/packages/nextra-theme-docs/__test__/normalize-page.spec.ts +++ b/packages/nextra-theme-docs/__test__/normalize-page.spec.ts @@ -56,7 +56,7 @@ describe('normalize-page', () => { { name: 'get-started', route: '/get-started' }, { name: 'index', route: '/' }, { - name: 'meta.json', + name: '_meta.json', route: '', meta: { '404': { @@ -89,7 +89,7 @@ describe('normalize-page', () => { { name: 'get-started', route: '/get-started' }, { name: 'index', route: '/' }, { - name: 'meta.json', + name: '_meta.json', route: '', meta: { '500': { diff --git a/packages/nextra-theme-docs/src/components/nav-links.tsx b/packages/nextra-theme-docs/src/components/nav-links.tsx index f7b7262396..c552a80626 100644 --- a/packages/nextra-theme-docs/src/components/nav-links.tsx +++ b/packages/nextra-theme-docs/src/components/nav-links.tsx @@ -32,13 +32,7 @@ export const NavLinks = ({ 'rtl:ml-2 ltr:mr-2' )} > - + {prev.title} ) : null} @@ -54,13 +48,7 @@ export const NavLinks = ({ )} > {next.title} - + ) : null} diff --git a/packages/nextra-theme-docs/src/components/navbar.tsx b/packages/nextra-theme-docs/src/components/navbar.tsx index 63aa1ec9c8..4dbc074afa 100644 --- a/packages/nextra-theme-docs/src/components/navbar.tsx +++ b/packages/nextra-theme-docs/src/components/navbar.tsx @@ -111,11 +111,8 @@ export function Navbar({ flatDirectories, items }: NavBarProps): ReactElement { > {menu.title} path]:origin-center [&>path]:transition-transform [&>path]:rotate-90' - )} + className="h-[18px] min-w-[18px] rounded-sm p-0.5" + pathClassName="origin-center transition-transform rotate-90" /> diff --git a/packages/nextra-theme-docs/src/components/sidebar.tsx b/packages/nextra-theme-docs/src/components/sidebar.tsx index fe67155b55..6244fc0731 100644 --- a/packages/nextra-theme-docs/src/components/sidebar.tsx +++ b/packages/nextra-theme-docs/src/components/sidebar.tsx @@ -52,51 +52,12 @@ function FolderImpl({ item, anchors }: FolderProps) { } }, [activeRouteInside]) - const link = ( - { - const clickedToggleIcon = ['svg', 'path'].includes( - (e.target as HTMLElement).tagName.toLowerCase() - ) - if (clickedToggleIcon) { - e.preventDefault() - } - if ((item as Item).withIndexPage) { - // If it's focused, we toggle it. Otherwise, always open it. - if (active || clickedToggleIcon) { - TreeState[item.route] = !open - } else { - TreeState[item.route] = true - setMenu(false) - } - rerender({}) - return - } - if (active) return - TreeState[item.route] = !open - rerender({}) - }} - > - {item.title} - path]:origin-center [&>path]:transition-transform rtl:[&>path]:-rotate-180', - open && 'ltr:[&>path]:rotate-90 rtl:[&>path]:rotate-[-270deg]' - )} - /> - - ) - if (item.type === 'menu') { const menu = item as MenuItem const routes = Object.fromEntries( (menu.children || []).map(route => [route.name, route]) ) - const directories = Object.entries(menu.items || {}).map(([key, item]) => { + item.children = Object.entries(menu.items || {}).map(([key, item]) => { const route = routes[key] || { name: key, locale: menu.locale, @@ -107,25 +68,48 @@ function FolderImpl({ item, anchors }: FolderProps) { ...item } }) - - return ( -
  • - {link} - - - -
  • - ) } - return (
  • - {link} + child.route)?.route + } + className="cursor-pointer !flex gap-2 items-center justify-between [word-break:break-word]" + onClick={e => { + const clickedToggleIcon = ['svg', 'path'].includes( + (e.target as HTMLElement).tagName.toLowerCase() + ) + if (clickedToggleIcon) { + e.preventDefault() + } + if ((item as Item).withIndexPage) { + // If it's focused, we toggle it. Otherwise, always open it. + if (active || clickedToggleIcon) { + TreeState[item.route] = !open + } else { + TreeState[item.route] = true + setMenu(false) + } + rerender({}) + return + } + if (active) return + TreeState[item.route] = !open + rerender({}) + }} + > + {item.title} + + {Array.isArray(item.children) ? ( const ConfigContext = createContext({ title: '', - meta: {}, + frontMatter: {}, ...DEFAULT_THEME }) @@ -80,7 +80,7 @@ export const ConfigProvider = ({ unstable_flexsearch: pageOpts.unstable_flexsearch, newNextLinkBehavior: pageOpts.newNextLinkBehavior, title: pageOpts.title, - meta: pageOpts.meta, + frontMatter: pageOpts.frontMatter, ...Object.fromEntries( DEEP_OBJECT_KEYS.map(key => [ key, diff --git a/packages/nextra-theme-docs/src/index.tsx b/packages/nextra-theme-docs/src/index.tsx index 3537117b0b..3de034b471 100644 --- a/packages/nextra-theme-docs/src/index.tsx +++ b/packages/nextra-theme-docs/src/index.tsx @@ -15,7 +15,6 @@ import { Navbar, NavLinks, Sidebar, - TOC, Breadcrumb, Banner } from './components' @@ -141,7 +140,7 @@ const Body = ({ const InnerLayout = ({ filePath, pageMap, - meta, + frontMatter, headings, timestamp, children @@ -173,7 +172,7 @@ const InnerLayout = ({ document.documentElement.setAttribute('dir', direction) }, []) - const themeContext = { ...activeThemeContext, ...meta } + const themeContext = { ...activeThemeContext, ...frontMatter } const hideSidebar = !themeContext.sidebar || themeContext.layout === 'raw' const asPopover = activeType === 'page' || hideSidebar @@ -190,7 +189,7 @@ const InnerLayout = ({
    {renderComponent(config.toc.component, { headings: config.toc.float ? headings : [], - filePath, + filePath })}
    ) diff --git a/packages/nextra-theme-docs/src/utils/normalize-pages.ts b/packages/nextra-theme-docs/src/utils/normalize-pages.ts index 49882306ad..70842bf5ae 100644 --- a/packages/nextra-theme-docs/src/utils/normalize-pages.ts +++ b/packages/nextra-theme-docs/src/utils/normalize-pages.ts @@ -1,6 +1,6 @@ import { PageMapItem } from 'nextra' import getTitle from 'title' -import { DEFAULT_PAGE_THEME } from '../constants' +import { DEFAULT_PAGE_THEME, META_FILENAME } from '../constants' import { PageTheme } from '../types' function extendMeta( @@ -87,7 +87,7 @@ export function normalizePages({ }) { let _meta: Record | undefined for (let item of list) { - if (item.name === 'meta.json') { + if (item.name === META_FILENAME) { if (locale === item.locale) { _meta = item.meta break @@ -133,12 +133,12 @@ export function normalizePages({ delete fallbackMeta.title delete fallbackMeta.href - // Normalize items based on files and meta.json. + // Normalize items based on files and _meta.json. const items = list .filter( a => // not meta - a.name !== 'meta.json' && + a.name !== META_FILENAME && // not hidden routes !a.name.startsWith('_') && // locale matches, or fallback to default locale diff --git a/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap b/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap index 4ac26514b8..17fd1f72bd 100644 --- a/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap +++ b/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap @@ -14,17 +14,82 @@ exports[`Page Process > pageMap en-US 1`] = ` "route": "/500", }, { - "children": [ - { - "locale": "en-US", - "name": "a-page", - "route": "/about/a-page", + "locale": "en-US", + "meta": { + "404": { + "theme": { + "timestamp": false, + }, + "type": "page", }, - { - "locale": "en-US", - "name": "acknowledgement", - "route": "/about/acknowledgement", + "500": { + "theme": { + "layout": "full", + "timestamp": false, + }, + "type": "page", + }, + "about": { + "items": { + "a-page": { + "title": "A Page", + }, + "acknowledgement": { + "title": "Acknowledgement", + }, + "contributors": { + "href": "https://github.com/vercel/swr/graphs/contributors", + "newWindow": true, + "title": "Contributors", + }, + "team": { + "title": "Team", + }, + }, + "title": "About", + "type": "menu", + }, + "blog": { + "theme": { + "breadcrumb": false, + "footer": true, + "sidebar": false, + "toc": true, + "typesetting": "article", + }, + "title": "Blog", + "type": "page", + }, + "docs": { + "theme": { + "toc": true, + }, + "title": "Docs", + "type": "page", + }, + "examples": { + "theme": { + "layout": "full", + }, + "title": "Examples", + "type": "page", + }, + "index": { + "hidden": true, + "title": "Introduction", + "type": "page", + }, + "nextra_link": { + "href": "https://github.com/shuding/nextra", + "newWindow": true, + "title": "Nextra ↗", + "type": "page", }, + }, + "name": "_meta.json", + }, + { + "children": [ { "locale": "en-US", "meta": { @@ -39,7 +104,17 @@ exports[`Page Process > pageMap en-US 1`] = ` "acknowledgement": "🧩 Acknowledgement", "team": "👥 Team", }, - "name": "meta.json", + "name": "_meta.json", + }, + { + "locale": "en-US", + "name": "a-page", + "route": "/about/a-page", + }, + { + "locale": "en-US", + "name": "acknowledgement", + "route": "/about/acknowledgement", }, { "locale": "en-US", @@ -62,7 +137,7 @@ exports[`Page Process > pageMap en-US 1`] = ` "title": "Announcing SWR 1.0", }, }, - "name": "meta.json", + "name": "_meta.json", }, { "frontMatter": { @@ -93,27 +168,62 @@ exports[`Page Process > pageMap en-US 1`] = ` "route": "/docs/404-500", }, { - "children": [ - { - "locale": "en-US", - "name": "cache", - "route": "/docs/advanced/cache", + "locale": "en-US", + "meta": { + "--- hey": { + "title": "Getting Started", + "type": "separator", }, - { - "locale": "en-US", - "name": "code-highlighting", - "route": "/docs/advanced/code-highlighting", + "--- my_new_separator": { + "title": "Advanced", + "type": "separator", }, - { - "locale": "en-US", - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", + "404-500": "404/500 Custom Error Pages", + "advanced": { + "title": "Advanced", }, - { - "locale": "en-US", - "name": "markdown-import", - "route": "/docs/advanced/markdown-import", + "arguments": "Arguments", + "change-log": { + "theme": { + "sidebar": false, + }, + "title": "Change Log", + }, + "conditional-fetching": "Conditional Data Fetching", + "data-fetching": "Data Fetching", + "error-handling": { + "hidden": true, + "title": "Error Handling", + }, + "getting-started": "Getting Started", + "github_link": { + "href": "https://github.com/shuding/nextra", + "newWindow": true, + "title": "GitHub 🐙 →", + "type": "page", }, + "global-configuration": "Global Configuration", + "middleware": "Middleware", + "mutation": "Mutation", + "options": "Options", + "pagination": "Pagination", + "prefetching": "Prefetching", + "raw-layout": { + "theme": { + "layout": "raw", + }, + "title": "Raw Layout", + }, + "revalidation": "Auto Revalidation", + "scroll-with-dynamic-height": "Scroll With Dynamic Height", + "suspense": "Suspense", + "typescript": "TypeScript :)", + "with-nextjs": "Next.js SSG and SSR", + }, + "name": "_meta.json", + }, + { + "children": [ { "locale": "en-US", "meta": { @@ -134,7 +244,27 @@ exports[`Page Process > pageMap en-US 1`] = ` "performance": "Performance", "react-native": "React Native", }, - "name": "meta.json", + "name": "_meta.json", + }, + { + "locale": "en-US", + "name": "cache", + "route": "/docs/advanced/cache", + }, + { + "locale": "en-US", + "name": "code-highlighting", + "route": "/docs/advanced/code-highlighting", + }, + { + "locale": "en-US", + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "locale": "en-US", + "name": "markdown-import", + "route": "/docs/advanced/markdown-import", }, { "children": [ @@ -201,61 +331,6 @@ exports[`Page Process > pageMap en-US 1`] = ` "name": "global-configuration", "route": "/docs/global-configuration", }, - { - "locale": "en-US", - "meta": { - "--- hey": { - "title": "Getting Started", - "type": "separator", - }, - "--- my_new_separator": { - "title": "Advanced", - "type": "separator", - }, - "404-500": "404/500 Custom Error Pages", - "advanced": { - "title": "Advanced", - }, - "arguments": "Arguments", - "change-log": { - "theme": { - "sidebar": false, - }, - "title": "Change Log", - }, - "conditional-fetching": "Conditional Data Fetching", - "data-fetching": "Data Fetching", - "error-handling": { - "hidden": true, - "title": "Error Handling", - }, - "getting-started": "Getting Started", - "github_link": { - "href": "https://github.com/shuding/nextra", - "newWindow": true, - "title": "GitHub 🐙 →", - "type": "page", - }, - "global-configuration": "Global Configuration", - "middleware": "Middleware", - "mutation": "Mutation", - "options": "Options", - "pagination": "Pagination", - "prefetching": "Prefetching", - "raw-layout": { - "theme": { - "layout": "raw", - }, - "title": "Raw Layout", - }, - "revalidation": "Auto Revalidation", - "scroll-with-dynamic-height": "Scroll With Dynamic Height", - "suspense": "Suspense", - "typescript": "TypeScript :)", - "with-nextjs": "Next.js SSG and SSR", - }, - "name": "meta.json", - }, { "locale": "en-US", "name": "middleware", @@ -317,6 +392,23 @@ exports[`Page Process > pageMap en-US 1`] = ` }, { "children": [ + { + "locale": "en-US", + "meta": { + "auth": "Authentication", + "basic": "Basic Usage", + "error-handling": "Error Handling", + "full": { + "theme": { + "layout": "raw", + }, + "title": "Full", + }, + "infinite-loading": "Infinite Loading", + "ssr": "Next.js SSR", + }, + "name": "_meta.json", + }, { "frontMatter": { "full": true, @@ -358,23 +450,6 @@ exports[`Page Process > pageMap en-US 1`] = ` "name": "infinite-loading", "route": "/examples/infinite-loading", }, - { - "locale": "en-US", - "meta": { - "auth": "Authentication", - "basic": "Basic Usage", - "error-handling": "Error Handling", - "full": { - "theme": { - "layout": "raw", - }, - "title": "Full", - }, - "infinite-loading": "Infinite Loading", - "ssr": "Next.js SSR", - }, - "name": "meta.json", - }, { "frontMatter": { "full": true, @@ -397,102 +472,40 @@ exports[`Page Process > pageMap en-US 1`] = ` "name": "index", "route": "/", }, + ], + "/docs/data-fetching", + "Data Fetching", +] +`; + +exports[`Page Process > pageMap zh-CN 1`] = ` +[ + [ { - "locale": "en-US", + "locale": "zh-CN", "meta": { - "404": { - "theme": { - "timestamp": false, - }, - "type": "page", - }, - "500": { - "theme": { - "layout": "full", - "timestamp": false, - }, - "type": "page", - }, - "about": { - "items": { - "a-page": { - "title": "A Page", - }, - "acknowledgement": { - "title": "Acknowledgement", - }, - "contributors": { - "href": "https://github.com/vercel/swr/graphs/contributors", - "newWindow": true, - "title": "Contributors", - }, - "team": { - "title": "Team", - }, - }, - "title": "About", - "type": "menu", - }, "blog": { - "theme": { - "breadcrumb": false, - "footer": true, - "sidebar": false, - "toc": true, - "typesetting": "article", - }, - "title": "Blog", + "title": "博客", "type": "page", }, "docs": { - "theme": { - "toc": true, - }, - "title": "Docs", + "title": "文档", "type": "page", }, "examples": { - "theme": { - "layout": "full", - }, - "title": "Examples", + "title": "示例", "type": "page", }, "index": { "hidden": true, - "title": "Introduction", - "type": "page", - }, - "nextra_link": { - "href": "https://github.com/shuding/nextra", - "newWindow": true, - "title": "Nextra ↗", + "title": "简介", "type": "page", }, }, - "name": "meta.json", + "name": "_meta.json", }, - ], - "/docs/data-fetching", - "Data Fetching", -] -`; - -exports[`Page Process > pageMap zh-CN 1`] = ` -[ - [ { "children": [ - { - "locale": "en-US", - "name": "a-page", - "route": "/about/a-page", - }, - { - "locale": "en-US", - "name": "acknowledgement", - "route": "/about/acknowledgement", - }, { "locale": "en-US", "meta": { @@ -507,7 +520,17 @@ exports[`Page Process > pageMap zh-CN 1`] = ` "acknowledgement": "🧩 Acknowledgement", "team": "👥 Team", }, - "name": "meta.json", + "name": "_meta.json", + }, + { + "locale": "en-US", + "name": "a-page", + "route": "/about/a-page", + }, + { + "locale": "en-US", + "name": "acknowledgement", + "route": "/about/acknowledgement", }, { "locale": "en-US", @@ -525,7 +548,7 @@ exports[`Page Process > pageMap zh-CN 1`] = ` "meta": { "swr-v1": "SWR 1.0 发布", }, - "name": "meta.json", + "name": "_meta.json", }, { "frontMatter": { @@ -542,8 +565,42 @@ exports[`Page Process > pageMap zh-CN 1`] = ` }, { "children": [ + { + "locale": "zh-CN", + "meta": { + "advanced": "高级", + "arguments": "传入参数", + "change-log": "更新日志", + "conditional-fetching": "条件数据请求", + "data-fetching": "数据请求", + "error-handling": "错误处理", + "getting-started": "入门", + "global-configuration": "全局配置", + "middleware": "中间件", + "mutation": "数据更改", + "options": "选项", + "pagination": "分页", + "prefetching": "预请求", + "revalidation": "自动重新请求", + "scroll-with-dynamic-height": "以動態高度滾動", + "suspense": "Suspense", + "typescript": "Typescript", + "with-nextjs": "Next.js SSG 和 SSR", + }, + "name": "_meta.json", + }, { "children": [ + { + "locale": "zh-CN", + "meta": { + "cache": "缓存", + "file-name.with.DOTS": "带点的文件名", + "performance": "性能", + "react-native": "React Native", + }, + "name": "_meta.json", + }, { "locale": "zh-CN", "name": "cache", @@ -554,16 +611,6 @@ exports[`Page Process > pageMap zh-CN 1`] = ` "name": "file-name.with.DOTS", "route": "/docs/advanced/file-name.with.DOTS", }, - { - "locale": "zh-CN", - "meta": { - "cache": "缓存", - "file-name.with.DOTS": "带点的文件名", - "performance": "性能", - "react-native": "React Native", - }, - "name": "meta.json", - }, { "children": [ { @@ -634,30 +681,6 @@ exports[`Page Process > pageMap zh-CN 1`] = ` "name": "global-configuration", "route": "/docs/global-configuration", }, - { - "locale": "zh-CN", - "meta": { - "advanced": "高级", - "arguments": "传入参数", - "change-log": "更新日志", - "conditional-fetching": "条件数据请求", - "data-fetching": "数据请求", - "error-handling": "错误处理", - "getting-started": "入门", - "global-configuration": "全局配置", - "middleware": "中间件", - "mutation": "数据更改", - "options": "选项", - "pagination": "分页", - "prefetching": "预请求", - "revalidation": "自动重新请求", - "scroll-with-dynamic-height": "以動態高度滾動", - "suspense": "Suspense", - "typescript": "Typescript", - "with-nextjs": "Next.js SSG 和 SSR", - }, - "name": "meta.json", - }, { "locale": "zh-CN", "name": "middleware", @@ -729,6 +752,17 @@ exports[`Page Process > pageMap zh-CN 1`] = ` }, { "children": [ + { + "locale": "zh-CN", + "meta": { + "auth": "身份验证", + "basic": "基本用法", + "error-handling": "错误处理", + "infinite-loading": "无限加载", + "ssr": "Next.js SSR", + }, + "name": "_meta.json", + }, { "frontMatter": { "full": true, @@ -765,17 +799,6 @@ exports[`Page Process > pageMap zh-CN 1`] = ` "name": "infinite-loading", "route": "/examples/infinite-loading", }, - { - "locale": "zh-CN", - "meta": { - "auth": "身份验证", - "basic": "基本用法", - "error-handling": "错误处理", - "infinite-loading": "无限加载", - "ssr": "Next.js SSR", - }, - "name": "meta.json", - }, { "locale": "en-US", "name": "full", @@ -802,29 +825,6 @@ exports[`Page Process > pageMap zh-CN 1`] = ` "name": "index", "route": "/", }, - { - "locale": "zh-CN", - "meta": { - "blog": { - "title": "博客", - "type": "page", - }, - "docs": { - "title": "文档", - "type": "page", - }, - "examples": { - "title": "示例", - "type": "page", - }, - "index": { - "hidden": true, - "title": "简介", - "type": "page", - }, - }, - "name": "meta.json", - }, { "locale": "", "name": "404", diff --git a/packages/nextra/src/constants.ts b/packages/nextra/src/constants.ts index 69d322aa8e..02a63d693e 100644 --- a/packages/nextra/src/constants.ts +++ b/packages/nextra/src/constants.ts @@ -7,3 +7,5 @@ export const LOCALE_REGEX = /\.([a-z]{2}(-[A-Z]{2})?)$/ export const DEFAULT_LOCALE = 'en-US' export const OFFICIAL_THEMES = ['nextra-theme-docs', 'nextra-theme-blog'] + +export const META_FILENAME = '_meta.json' diff --git a/packages/nextra/src/content-dump.ts b/packages/nextra/src/content-dump.ts index 9fc53e7842..3690579dd4 100644 --- a/packages/nextra/src/content-dump.ts +++ b/packages/nextra/src/content-dump.ts @@ -1,5 +1,6 @@ import fs from 'graceful-fs' import path from 'path' +import { PageOpts } from './types' const { statSync, mkdirSync } = fs @@ -40,20 +41,20 @@ export function addPage({ fileLocale, route, title, - meta, + frontMatter, structurizedData }: { fileLocale: string route: string title: string - meta: Record + frontMatter: PageOpts['frontMatter'] structurizedData: any }): void { const dataFilename = `nextra-data-${fileLocale}.json` asset[fileLocale] ||= initFromCache(dataFilename) asset[fileLocale][route] = { - title: title || meta.title, + title: title || frontMatter.title, data: structurizedData } diff --git a/packages/nextra/src/context.ts b/packages/nextra/src/context.ts index 7b8381e434..dea6668b6a 100644 --- a/packages/nextra/src/context.ts +++ b/packages/nextra/src/context.ts @@ -1,3 +1,5 @@ +import { META_FILENAME } from './constants' + interface Page { name: string route: string @@ -31,12 +33,12 @@ function normalizeMeta(meta: any) { function filter(pageMap: any, activeLevel?: string) { let activeLevelPages: Page[] | undefined - let meta = pageMap.find((item: any) => item.name === 'meta.json')?.meta || {} + let meta = pageMap.find((item: any) => item.name === META_FILENAME)?.meta || {} const metaKeys = Object.keys(meta) const items: Page[] = [] for (const item of pageMap) { - if (item.name === 'meta.json') continue + if (item.name === META_FILENAME) continue const page: Page = { ...item, meta: normalizeMeta(meta[item.name]) diff --git a/packages/nextra/src/icons/arrow-right.tsx b/packages/nextra/src/icons/arrow-right.tsx index 9699025971..d35b5d8963 100644 --- a/packages/nextra/src/icons/arrow-right.tsx +++ b/packages/nextra/src/icons/arrow-right.tsx @@ -1,6 +1,9 @@ -import React, { ComponentProps } from 'react' +import React, { ComponentProps, ReactElement } from 'react' -export function ArrowRightIcon(props: ComponentProps<'svg'>) { +export function ArrowRightIcon({ + pathClassName, + ...props +}: ComponentProps<'svg'> & { pathClassName?: string }): ReactElement { return ( ) { strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7" + className={pathClassName} /> ) diff --git a/packages/nextra/src/loader.ts b/packages/nextra/src/loader.ts index 629bc6d76b..2e856b36bf 100644 --- a/packages/nextra/src/loader.ts +++ b/packages/nextra/src/loader.ts @@ -16,7 +16,8 @@ import { IS_PRODUCTION, DEFAULT_LOCALE, OFFICIAL_THEMES, - MARKDOWN_EXTENSION_REGEX + MARKDOWN_EXTENSION_REGEX, + META_FILENAME } from './constants' // TODO: create this as a webpack plugin. @@ -96,7 +97,7 @@ async function loader( const fileLocale = parseFileName(resourcePath).locale for (const [filePath, { name, locale }] of Object.entries(fileMap)) { - if (name === 'meta.json' && (!fileLocale || locale === fileLocale)) { + if (name === META_FILENAME && (!fileLocale || locale === fileLocale)) { context.addDependency(filePath) } } @@ -105,7 +106,7 @@ async function loader( context.addContextDependency(pagesDir) // Extract frontMatter information if it exists - const { data: meta, content } = grayMatter(source) + const { data: frontMatter, content } = grayMatter(source) const { result, headings, structurizedData, hasJsxInH1 } = await compileMdx( content, @@ -138,12 +139,12 @@ export default MDXContent`.trimStart() const skipFlexsearchIndexing = IS_PRODUCTION && indexContentEmitted.has(resourcePath) if (unstable_flexsearch && !skipFlexsearchIndexing) { - if (meta.searchable !== false) { + if (frontMatter.searchable !== false) { addPage({ fileLocale: fileLocale || DEFAULT_LOCALE, route, title, - meta, + frontMatter, structurizedData }) } @@ -172,7 +173,7 @@ export default MDXContent`.trimStart() const pageOpts: Omit = { filePath: path.relative(process.cwd(), resourcePath), route: slash(route), - meta, + frontMatter, pageMap, headings, hasJsxInH1, @@ -216,7 +217,7 @@ export default __nextra_withLayout__( ${JSON.stringify(pageNextRoute)}, Content, { - title: __nextra_pageOpts__.meta.title + title: __nextra_pageOpts__.frontMatter.title || (typeof __nextra_title__ === 'string' && __nextra_title__) || 'Untitled', ...__nextra_pageOpts__ diff --git a/packages/nextra/src/page-map.ts b/packages/nextra/src/page-map.ts index 1a2a881a5e..7de51ef71e 100644 --- a/packages/nextra/src/page-map.ts +++ b/packages/nextra/src/page-map.ts @@ -2,6 +2,7 @@ import { PageMapItem } from './types' import { parseFileName } from './utils' import path from 'path' import filterRouteLocale from './filter-route-locale' +import { META_FILENAME } from './constants' export function getPageMap( currentResourcePath: string, @@ -9,19 +10,17 @@ export function getPageMap( fileMap: Record, defaultLocale: string ): [PageMapItem[], string, string] { - const activeRouteLocale = parseFileName(currentResourcePath).locale + const { locale } = parseFileName(currentResourcePath) const pageItem = fileMap[currentResourcePath] + const [metaName, metaExt] = META_FILENAME.split('.') const metaPath = path.dirname(currentResourcePath) - const metaExtension = activeRouteLocale ? `${activeRouteLocale}.json` : `json` - const pageMeta = - fileMap[`${metaPath}/meta.${metaExtension}`]?.meta?.[pageItem.name] + const metaFilename = `${metaName}.${locale && `${locale}.`}${metaExt}` + const pageMeta = fileMap[`${metaPath}/${metaFilename}`]?.meta?.[pageItem.name] const title = (typeof pageMeta === 'string' ? pageMeta : pageMeta?.title) || pageItem.name return [ - activeRouteLocale - ? filterRouteLocale(pageMap, activeRouteLocale, defaultLocale) - : pageMap, + locale ? filterRouteLocale(pageMap, locale, defaultLocale) : pageMap, pageItem.route, title ] diff --git a/packages/nextra/src/plugin.ts b/packages/nextra/src/plugin.ts index 3d59d5932a..f9cbdc8290 100644 --- a/packages/nextra/src/plugin.ts +++ b/packages/nextra/src/plugin.ts @@ -9,7 +9,7 @@ import { findPagesDir } from 'next/dist/lib/find-pages-dir.js' import { Compiler } from 'webpack' import { restoreCache } from './content-dump' -import { MARKDOWN_EXTENSION_REGEX } from './constants' +import { MARKDOWN_EXTENSION_REGEX, META_FILENAME } from './constants' const readdir = promisify(fs.readdir) const readFile = promisify(fs.readFile) @@ -56,16 +56,24 @@ export async function collectFiles( fileMap[filePath] = await collectMdx(filePath, fileRoute) return fileMap[filePath] } + const fileName = name + ext - if (ext === '.json' && name === 'meta') { + if (fileName === META_FILENAME) { const content = await readFile(filePath, 'utf8') fileMap[filePath] = { - name: 'meta.json', + name: META_FILENAME, locale, meta: parseJsonFile(content, filePath) } return fileMap[filePath] } + + if (fileName === 'meta.json') { + console.warn( + `[nextra] "meta.json" was renamed to "_meta.json". Rename the following file:`, + path.relative(process.cwd(), filePath) + ) + } }) ) ).filter(Boolean) diff --git a/packages/nextra/src/types.ts b/packages/nextra/src/types.ts index 8907c0425d..f37d851e28 100644 --- a/packages/nextra/src/types.ts +++ b/packages/nextra/src/types.ts @@ -50,7 +50,7 @@ export type Heading = MDASTHeading & { export type PageOpts = { filePath: string route: string - meta: GrayMatterFile['data'] + frontMatter: GrayMatterFile['data'] pageMap: PageMapItem[] title: string headings: Heading[]