Skip to content

Commit 21cb30d

Browse files
committed
feat: auto replace element with geist component
1 parent 67c6c07 commit 21cb30d

File tree

7 files changed

+126
-3
lines changed

7 files changed

+126
-3
lines changed

lib/components/mdx/hybrid-code.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React, { ReactNode, useMemo } from 'react'
2+
import { Code, CodeProps } from '@geist-ui/core'
3+
4+
export type HybridCodeProps = CodeProps
5+
export const FILE_NAME_PREFIX = '// NAME:'
6+
type HybridCodeChildrenAndName = {
7+
children: ReactNode | undefined
8+
name?: string | undefined
9+
}
10+
11+
const extractFileName = (
12+
children: ReactNode | undefined,
13+
stopDeep: boolean = false,
14+
): HybridCodeChildrenAndName => {
15+
if (!children) return { children }
16+
let name: string | undefined = undefined
17+
const next = React.Children.map(children, child => {
18+
if (name) return child
19+
if (!React.isValidElement(child)) return null
20+
const grandson = child.props?.children
21+
if (typeof grandson === 'string' && grandson?.startsWith(FILE_NAME_PREFIX)) {
22+
name = grandson
23+
return null
24+
}
25+
if (!Array.isArray(grandson) || stopDeep) return child
26+
27+
const { children: puredGrandson, name: puredName } = extractFileName(
28+
child.props?.children,
29+
true,
30+
)
31+
if (!puredName) return child
32+
33+
name = puredName
34+
const withoutSpaceAndNull = React.Children.toArray(puredGrandson).filter(
35+
(r, index) => {
36+
if (index === 0 && r === '\n') return false
37+
return !!r
38+
},
39+
)
40+
return React.cloneElement(child, {
41+
children: withoutSpaceAndNull,
42+
})
43+
})
44+
return {
45+
children: next,
46+
name,
47+
}
48+
}
49+
50+
const HybridCode: React.FC<HybridCodeProps> = ({ children }) => {
51+
const { children: withoutNameChildren, name } = useMemo<HybridCodeChildrenAndName>(
52+
() => extractFileName(children),
53+
[children],
54+
)
55+
const withoutPrefixName = useMemo(() => {
56+
if (!name) return name
57+
return name.replace(FILE_NAME_PREFIX, '')
58+
}, [name])
59+
60+
return (
61+
<Code block name={withoutPrefixName}>
62+
{withoutNameChildren}
63+
</Code>
64+
)
65+
}
66+
67+
export default HybridCode

lib/components/mdx/hybrid-link.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react'
2+
import NextLink from 'next/link'
3+
import { Link, LinkProps } from '@geist-ui/core'
4+
5+
export type HybridLinkProps = LinkProps
6+
7+
const HybridLink: React.FC<HybridLinkProps> = ({ href = '#', children, ...props }) => {
8+
const isRelativeUrl = !/^([a-z0-9]*:|.{0})\/\/.*$/gim.test(href)
9+
10+
if (isRelativeUrl) {
11+
return (
12+
<NextLink href={href} passHref>
13+
<Link color block {...props}>
14+
{children}
15+
</Link>
16+
</NextLink>
17+
)
18+
}
19+
20+
return (
21+
<Link href={href} target="_blank" color rel="noreferrer nofollow" {...props}>
22+
{children}
23+
</Link>
24+
)
25+
}
26+
27+
export default HybridLink

lib/components/mdx/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as HybridLink } from './hybrid-link'
2+
export { default as HybridCode } from './hybrid-code'

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"@geist-ui/core": "^2.3.4",
1616
"@geist-ui/icons": "^1.0.1",
1717
"@geist-ui/prism": "^1.1.1",
18+
"@mdx-js/react": "^2.0.0",
1819
"@unix/views": "^0.2.0",
1920
"ms": "^2.1.3",
2021
"next": "^12.1.0",

pages/_app.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import { NextPage } from 'next'
33
import { AppProps } from 'next/app'
44
import BLOG from '../blog.config'
55
import useDomClean from 'lib/use-dom-clean'
6+
import { MDXProvider } from '@mdx-js/react'
67
import { PrismBaseline } from '@geist-ui/prism'
7-
import { GeistProvider, CssBaseline } from '@geist-ui/core'
8+
import { GeistProvider, CssBaseline, Image } from '@geist-ui/core'
89
import { useCallback, useState, useEffect, useMemo } from 'react'
910
import { getDNSPrefetchValue } from 'lib/data-transform'
1011
import { BlogConfigsProvider } from 'lib/components'
12+
import { HybridLink, HybridCode } from 'lib/components/mdx'
1113

1214
const Application: NextPage<AppProps<{}>> = ({ Component, pageProps }) => {
1315
const [themeType, setThemeType] = useState('light')
@@ -58,7 +60,14 @@ const Application: NextPage<AppProps<{}>> = ({ Component, pageProps }) => {
5860
<CssBaseline />
5961
<PrismBaseline />
6062
<BlogConfigsProvider onChange={changeHandle}>
61-
<Component {...pageProps} />
63+
<MDXProvider
64+
components={{
65+
a: HybridLink,
66+
img: Image,
67+
pre: HybridCode,
68+
}}>
69+
<Component {...pageProps} />
70+
</MDXProvider>
6271
</BlogConfigsProvider>
6372
<style global jsx>{`
6473
@media only screen and (max-width: 767px) {

typings/mdx.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,12 @@ declare module '*.mdx' {
33
export default MDXComponent
44
}
55

6+
declare module "@mdx-js/react" {
7+
import { ComponentType, StyleHTMLAttributes } from "react"
8+
9+
type MDXProps = {
10+
children: React.ReactNode
11+
components: { [key:? string]: React.ReactNode, }
12+
}
13+
export class MDXProvider extends React.Component<MDXProps> {}
14+
}

yarn.lock

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,14 @@
308308
unist-util-visit "^4.0.0"
309309
vfile "^5.0.0"
310310

311+
"@mdx-js/react@^2.0.0":
312+
version "2.0.0"
313+
resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-2.0.0.tgz#00a9f5467d2761fe3818222740f50403f83aee2c"
314+
integrity sha512-icpMd43xqORnHSVRwALZv3ELN3IS7VS3BL+FyH2FFergQPSQ21FX0lN+OMIs0X+3dGY1L0DLhBCkMfPO+yDG7Q==
315+
dependencies:
316+
"@types/mdx" "^2.0.0"
317+
"@types/react" ">=16"
318+
311319
312320
version "12.1.0"
313321
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314"
@@ -468,7 +476,7 @@
468476
"@types/prop-types" "*"
469477
csstype "^3.0.2"
470478

471-
"@types/react@^17.0.39":
479+
"@types/react@>=16", "@types/react@^17.0.39":
472480
version "17.0.39"
473481
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce"
474482
integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==

0 commit comments

Comments
 (0)