Skip to content

Commit

Permalink
[nextra]: refactor loaders.ts, provide type for PageOpts in loader (
Browse files Browse the repository at this point in the history
#579)

* chore(nextra/blog/docs): provide types for PageOpts in loader

* yet more readable

* move `shallow cloned` console messages outside of loader
  • Loading branch information
dimaMachina committed Jul 30, 2022
1 parent bf74201 commit 0f4795f
Show file tree
Hide file tree
Showing 17 changed files with 170 additions and 191 deletions.
7 changes: 7 additions & 0 deletions .changeset/strange-fishes-marry.md
@@ -0,0 +1,7 @@
---
'nextra': patch
'nextra-theme-blog': patch
'nextra-theme-docs': patch
---

chore(nextra/blog/docs): provide types for PageOpts in loader
8 changes: 4 additions & 4 deletions packages/nextra-theme-blog/__test__/__fixture__/pageMap.ts
@@ -1,5 +1,5 @@
import { BlogPageOpt } from '../../src/types'
export const indexOpts: BlogPageOpt = {
import { BlogPageOpts } from '../../src/types'
export const indexOpts: BlogPageOpts = {
filename: 'index.mdx',
route: '/',
meta: {
Expand Down Expand Up @@ -102,7 +102,7 @@ export const indexOpts: BlogPageOpt = {
]
}

export const postsOpts: BlogPageOpt = {
export const postsOpts: BlogPageOpts = {
filename: 'index.md',
route: '/posts',
meta: {
Expand Down Expand Up @@ -205,7 +205,7 @@ export const postsOpts: BlogPageOpt = {
]
}

export const articleOpts: BlogPageOpt = {
export const articleOpts: BlogPageOpts = {
filename: 'aaron-swartz-a-programmable-web.mdx',
route: '/posts/aaron-swartz-a-programmable-web',
meta: {
Expand Down
7 changes: 3 additions & 4 deletions packages/nextra-theme-blog/src/blog-context.tsx
@@ -1,15 +1,14 @@
import React, { useContext } from 'react'
import { createContext, PropsWithChildren } from 'react'
import React, { ReactElement, useContext, createContext, ReactNode } from 'react'
import { LayoutProps } from './types'
import { isValidDate } from './utils/date'

const BlogContext = createContext<LayoutProps | null>(null)

export const BlogProvider: React.FC<PropsWithChildren<LayoutProps>> = ({
export const BlogProvider = ({
config,
children,
opts
}) => {
}: LayoutProps & { children: ReactNode }): ReactElement => {
const { date } = opts.meta

if (date && !isValidDate(date)) {
Expand Down
7 changes: 7 additions & 0 deletions packages/nextra-theme-blog/src/constants.tsx
@@ -0,0 +1,7 @@
import React from 'react'
import { NextraBlogTheme } from './types'

export const DEFAULT_CONFIG: NextraBlogTheme = {
readMore: 'Read More →',
footer: <small className="block mt-32">CC BY-NC 4.0 2022 © Shu Ding.</small>
}
31 changes: 11 additions & 20 deletions packages/nextra-theme-blog/src/index.tsx
@@ -1,11 +1,12 @@
import React, { PropsWithChildren, ReactNode } from 'react'
import React, { ReactElement, ReactNode } from 'react'
import { ThemeProvider } from 'next-themes'
import type { PageOpt } from 'nextra'
import type { PageOpts } from 'nextra'
import type { LayoutProps, NextraBlogTheme } from './types'
import { BlogProvider } from './blog-context'
import { ArticleLayout } from './article-layout'
import { PostsLayout } from './posts-layout'
import { PageLayout } from './page-layout'
import { DEFAULT_CONFIG } from './constants'

const layoutMap = {
post: ArticleLayout,
Expand All @@ -14,11 +15,11 @@ const layoutMap = {
tag: PostsLayout
}

const BlogLayout: React.FC<PropsWithChildren<LayoutProps>> = ({
const BlogLayout = ({
config,
children,
opts
}) => {
}: LayoutProps & { children: ReactNode }): ReactElement => {
const type = opts.meta.type || 'post'
const Layout = layoutMap[type]
if (!Layout) {
Expand All @@ -33,27 +34,17 @@ const BlogLayout: React.FC<PropsWithChildren<LayoutProps>> = ({
)
}

const createLayout = (opts: PageOpt, _config: NextraBlogTheme) => {
const config: NextraBlogTheme = Object.assign(
{
readMore: 'Read More →',
footer: (
<small className="mt-32 block">CC BY-NC 4.0 2022 © Shu Ding.</small>
),
titleSuffix: null,
postFooter: null
},
_config
)
const Page = ({ children }: { children: ReactNode }) => children
const Layout = (page: ReactNode) => (
const createLayout = (opts: PageOpts, config: NextraBlogTheme) => {
const extendedConfig = { ...DEFAULT_CONFIG, ...config }

const Page = ({ children }: { children: ReactNode }): ReactNode => children
Page.getLayout = (page: ReactNode): ReactElement => (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<BlogLayout config={config} opts={opts}>
<BlogLayout config={extendedConfig} opts={opts}>
{page}
</BlogLayout>
</ThemeProvider>
)
Page.getLayout = Layout
return Page
}

Expand Down
28 changes: 16 additions & 12 deletions packages/nextra-theme-blog/src/types.ts
@@ -1,4 +1,4 @@
import { PageOpt } from 'nextra'
import { PageOpts } from 'nextra'

export interface NextraBlogTheme {
readMore?: string
Expand All @@ -23,18 +23,22 @@ export interface NextraBlogTheme {
name: string
}[]
}
export interface BlogPageOpt extends PageOpt {
meta: {
title?: string
type?: 'post' | 'page' | 'posts' | 'tag'
tag?: string | string[]
back?: string
date?: string
description?: string
author?: string
}

export interface BlogPageOpts extends PageOpts {
meta: Meta
}

type Meta = {
title?: string
type?: 'post' | 'page' | 'posts' | 'tag'
tag?: string | string[]
back?: string
date?: string
description?: string
author?: string
}

export interface LayoutProps {
config: NextraBlogTheme
opts: BlogPageOpt
opts: BlogPageOpts
}
3 changes: 1 addition & 2 deletions packages/nextra-theme-blog/src/utils/collect.ts
Expand Up @@ -10,8 +10,7 @@ const isPost = (page: PageMapItem) => {
if (page.children) return false
if (page.name.startsWith('_')) return false
return (
!page.frontMatter ||
!page.frontMatter.type ||
!page.frontMatter?.type ||
page.frontMatter.type === 'post'
)
}
Expand Down
12 changes: 7 additions & 5 deletions packages/nextra-theme-docs/src/config.ts
@@ -1,8 +1,10 @@
import { PageOpt } from 'nextra'
import React from 'react'
import { PageOpts } from 'nextra'
import { createContext, useContext } from 'react'
import { DocsThemeConfig } from './types'

interface Config extends DocsThemeConfig {
unstable_flexsearch?: PageOpt['unstable_flexsearch']
unstable_flexsearch?: PageOpts['unstable_flexsearch']
}
export const ThemeConfigContext = React.createContext<Config>({})
export const useConfig = () => React.useContext(ThemeConfigContext)

export const ThemeConfigContext = createContext<Config>({})
export const useConfig = () => useContext(ThemeConfigContext)
4 changes: 2 additions & 2 deletions packages/nextra-theme-docs/src/head.tsx
Expand Up @@ -4,12 +4,12 @@ import { useTheme } from 'next-themes'

import renderComponent from './utils/render-component'
import { useConfig } from './config'
import { Meta } from './types'
import { PageOpts } from 'nextra'

interface HeadProps {
title: string
locale: string
meta: Meta
meta: PageOpts['meta']
}

export default function Head({ title, locale, meta }: HeadProps) {
Expand Down
59 changes: 26 additions & 33 deletions packages/nextra-theme-docs/src/index.tsx
@@ -1,5 +1,6 @@
import React, {
PropsWithChildren,
ReactElement,
ReactNode,
useEffect,
useMemo,
useRef,
Expand All @@ -9,7 +10,7 @@ import { useRouter } from 'next/router'
import 'focus-visible'
import { SkipNavContent } from '@reach/skip-nav'
import { ThemeProvider } from 'next-themes'
import { Heading, PageMapItem, PageOpt } from 'nextra'
import { PageMapItem, PageOpts } from 'nextra'
import cn from 'classnames'
import Head from './head'
import Navbar from './navbar'
Expand All @@ -23,7 +24,7 @@ import defaultConfig from './misc/default.config'
import { getFSRoute } from './utils/get-fs-route'
import { MenuContext } from './utils/menu-context'
import normalizePages from './utils/normalize-pages'
import { DocsThemeConfig, Meta, PageTheme } from './types'
import { DocsThemeConfig, PageTheme } from './types'
import './polyfill'
import Breadcrumb from './breadcrumb'
import renderComponent from './utils/render-component'
Expand All @@ -47,13 +48,13 @@ if (typeof window !== 'undefined') {
}

function useDirectoryInfo(pageMap: PageMapItem[]) {
const { locale, defaultLocale, asPath } = useRouter()
const { locale = 'en-US', defaultLocale, asPath } = useRouter()

return useMemo(() => {
const fsPath = getFSRoute(asPath, locale)
return normalizePages({
list: pageMap,
locale: locale ? locale : 'en-US',
locale,
defaultLocale,
route: fsPath
})
Expand All @@ -62,19 +63,20 @@ function useDirectoryInfo(pageMap: PageMapItem[]) {

interface BodyProps {
themeContext: PageTheme
breadcrumb?: React.ReactNode
toc?: React.ReactNode
breadcrumb?: ReactNode
toc?: ReactNode
timestamp?: number
navLinks: React.ReactNode
navLinks: ReactNode
children: ReactNode
}

const Body: React.FC<PropsWithChildren<BodyProps>> = ({
const Body = ({
themeContext,
breadcrumb,
navLinks,
timestamp,
children
}) => {
}: BodyProps): ReactElement => {
const config = useConfig()
const { locale = 'en-US' } = useRouter()
const date = timestamp ? new Date(timestamp) : null
Expand All @@ -91,7 +93,7 @@ const Body: React.FC<PropsWithChildren<BodyProps>> = ({
}, [])

return (
<React.Fragment>
<>
<SkipNavContent />
{themeContext.layout === 'full' ? (
<article className="nextra-body full relative justify-center overflow-x-hidden pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)]">
Expand Down Expand Up @@ -157,27 +159,19 @@ const Body: React.FC<PropsWithChildren<BodyProps>> = ({
</main>
</article>
)}
</React.Fragment>
</>
)
}
interface LayoutProps {
filename: string
pageMap: PageMapItem[]
meta: Meta
titleText: string | null
headings?: Heading[]
timestamp?: number
}

const Content: React.FC<PropsWithChildren<LayoutProps>> = ({
const Content = ({
filename,
pageMap,
meta,
titleText,
headings,
timestamp,
children
}) => {
}: PageOpts & { children: ReactNode }): ReactElement => {
const { route, locale = 'en-US' } = useRouter()
const config = useConfig()

Expand Down Expand Up @@ -207,8 +201,6 @@ const Content: React.FC<PropsWithChildren<LayoutProps>> = ({

const hideSidebar = !themeContext.sidebar || themeContext.layout === 'raw'
const hideToc = !themeContext.toc || themeContext.layout === 'raw'

const headingArr = headings ?? []
return (
<MenuContext.Provider
value={{
Expand Down Expand Up @@ -252,7 +244,7 @@ const Content: React.FC<PropsWithChildren<LayoutProps>> = ({
)
) : (
<ToC
headings={config.floatTOC ? headingArr : null}
headings={config.floatTOC ? headings : null}
filepathWithName={filepathWithName}
/>
)}
Expand Down Expand Up @@ -286,15 +278,16 @@ const Content: React.FC<PropsWithChildren<LayoutProps>> = ({
</MenuContext.Provider>
)
}
interface DocsLayoutProps extends PageOpt {
meta: Meta
}
const createLayout = (opts: DocsLayoutProps, config: DocsThemeConfig) => {
const extendedConfig = Object.assign({}, defaultConfig, config, opts)
const nextThemes = extendedConfig.nextThemes || {}
const Page = ({ children }: { children: React.ReactChildren }) => children

Page.getLayout = (page: any) => (
const createLayout = (opts: PageOpts, config: DocsThemeConfig) => {
const extendedConfig = {
...defaultConfig,
...config,
unstable_flexsearch: opts.unstable_flexsearch
}
const nextThemes = extendedConfig.nextThemes || {}
const Page = ({ children }: { children: ReactNode }): ReactNode => children
Page.getLayout = (page: ReactNode): ReactElement => (
<ThemeConfigContext.Provider value={extendedConfig}>
<ThemeProvider
attribute="class"
Expand Down
5 changes: 2 additions & 3 deletions packages/nextra-theme-docs/src/types.ts
Expand Up @@ -102,6 +102,5 @@ export type PageTheme = {
typesetting: 'default' | 'article'
breadcrumb: boolean
}
export interface Meta extends PageTheme {
title: string
}

type Meta = Record<string, any>
9 changes: 6 additions & 3 deletions packages/nextra/src/compile.ts
Expand Up @@ -4,8 +4,8 @@ import remarkGfm from 'remark-gfm'
import rehypePrettyCode from 'rehype-pretty-code'
import { rehypeMdxTitle } from 'rehype-mdx-title'
import { remarkStaticImage } from './mdx-plugins/static-image'
import { remarkHeadings, HeadingMeta } from './mdx-plugins/remark'
import { LoaderOptions } from './types'
import { remarkHeadings } from './mdx-plugins/remark'
import { LoaderOptions, PageOpts } from './types'
import structurize from './mdx-plugins/structurize'
import { parseMeta, attachMeta } from './mdx-plugins/rehype-handler'
import theme from './theme.json'
Expand Down Expand Up @@ -75,7 +75,10 @@ export async function compileMdx(
const result = await compiler.process(source)
return {
result: String(result),
...(compiler.data('headingMeta') as HeadingMeta),
...(compiler.data('headingMeta') as Pick<
PageOpts,
'headings' | 'hasJsxInH1'
>),
structurizedData
}
} catch (err) {
Expand Down

0 comments on commit 0f4795f

Please sign in to comment.