@primer/doctocat-nextjs 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{.eslintrc.js → .eslintrc.cjs} +2 -1
- package/.vscode/settings.json +5 -0
- package/CHANGELOG.md +30 -0
- package/components/context/color-modes/context.ts +2 -2
- package/components/layout/header/Header.tsx +15 -13
- package/components/layout/index-cards/IndexCards.tsx +3 -15
- package/components/layout/nav-drawer/useNavDrawerState.ts +6 -6
- package/components/layout/related-content-links/RelatedContentLinks.tsx +1 -3
- package/components/layout/root-layout/Theme.tsx +158 -122
- package/components/layout/sidebar/Sidebar.tsx +24 -33
- package/css/global.css +9 -94
- package/doctocat.config.js +6 -3
- package/helpers/hasChildren.ts +5 -0
- package/package.json +25 -17
- package/types.ts +13 -0
- package/components/mdx-components/mdx-components.module.css +0 -14
- package/components/mdx-components/mdx-components.tsx +0 -43
- /package/{.prettierrc.js → prettier.config.cjs} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @primer/doctocat-nextjs
|
|
2
2
|
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#18](https://github.com/primer/doctocat-nextjs/pull/18) [`bfe68b1`](https://github.com/primer/doctocat-nextjs/commit/bfe68b14e8e3b4383ea41dcbf47373df8a130567) Thanks [@rezrah](https://github.com/rezrah)! - Upgraded internal framework to [Nextra v3](https://the-guild.dev/blog/nextra-3).
|
|
8
|
+
|
|
9
|
+
To migrate Doctocat to this release, follow these steps:
|
|
10
|
+
|
|
11
|
+
1. Install the latest version `npm i @primer/doctocat-nextjs@0.1.0`
|
|
12
|
+
2. Rename your `next.config.js` to be `next.config.mjs`. Add `type="module"` to your `package.json` and update the file contents to match the following:
|
|
13
|
+
|
|
14
|
+
```diff
|
|
15
|
+
- const withDoctocat = require('@primer/doctocat-nextjs/doctocat.config.js')
|
|
16
|
+
|
|
17
|
+
- module.exports = {
|
|
18
|
+
- ...withDoctocat({
|
|
19
|
+
|
|
20
|
+
- }),
|
|
21
|
+
- }
|
|
22
|
+
|
|
23
|
+
+ import withDoctocat from '@primer/doctocat-nextjs/doctocat.config.js'
|
|
24
|
+
|
|
25
|
+
+ export default {
|
|
26
|
+
+ ...withDoctocat({
|
|
27
|
+
|
|
28
|
+
+ }),
|
|
29
|
+
+ }
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
|
|
3
33
|
## 0.0.4
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {createContext} from 'react'
|
|
2
2
|
|
|
3
3
|
export type ColorMode = 'light' | 'dark'
|
|
4
4
|
|
|
@@ -12,4 +12,4 @@ const defaultValues: ColorModeContextProps = {
|
|
|
12
12
|
setColorMode: () => {},
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export const ColorModeContext =
|
|
15
|
+
export const ColorModeContext = createContext<ColorModeContextProps>(defaultValues)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {MarkGithubIcon, MoonIcon, SearchIcon, SunIcon, ThreeBarsIcon, XIcon} from '@primer/octicons-react'
|
|
2
2
|
import {Box, FormControl, IconButton, TextInput} from '@primer/react'
|
|
3
3
|
import {Heading, Stack, Text} from '@primer/react-brand'
|
|
4
|
-
import clsx from 'clsx'
|
|
5
|
-
import {MdxFile, PageMapItem} from 'nextra'
|
|
4
|
+
import {clsx} from 'clsx'
|
|
5
|
+
import {MdxFile, Folder, PageMapItem} from 'nextra'
|
|
6
6
|
import type {PageItem} from 'nextra/normalize-pages'
|
|
7
|
-
import React, {useCallback, useEffect, useMemo} from 'react'
|
|
7
|
+
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
|
|
8
8
|
import {debounce} from 'lodash'
|
|
9
9
|
|
|
10
10
|
import Link from 'next/link'
|
|
@@ -12,6 +12,8 @@ import styles from './Header.module.css'
|
|
|
12
12
|
import {NavDrawer} from '../nav-drawer/NavDrawer'
|
|
13
13
|
import {useNavDrawerState} from '../nav-drawer/useNavDrawerState'
|
|
14
14
|
import {useColorMode} from '../../context/color-modes/useColorMode'
|
|
15
|
+
import {hasChildren} from '../../../helpers/hasChildren'
|
|
16
|
+
import {DocsItem} from '../../../types'
|
|
15
17
|
|
|
16
18
|
type HeaderProps = {
|
|
17
19
|
pageMap: PageMapItem[]
|
|
@@ -28,14 +30,14 @@ type SearchResults = {
|
|
|
28
30
|
|
|
29
31
|
export function Header({pageMap, docsDirectories, siteTitle}: HeaderProps) {
|
|
30
32
|
const {colorMode, setColorMode} = useColorMode()
|
|
31
|
-
const inputRef =
|
|
32
|
-
const searchResultsRef =
|
|
33
|
+
const inputRef = useRef<HTMLInputElement | null>(null)
|
|
34
|
+
const searchResultsRef = useRef<HTMLElement | null>(null)
|
|
33
35
|
const [isNavDrawerOpen, setIsNavDrawerOpen] = useNavDrawerState('768')
|
|
34
|
-
const [isSearchOpen, setIsSearchOpen] =
|
|
35
|
-
const [isSearchResultOpen, setIsSearchResultOpen] =
|
|
36
|
-
const [searchResults, setSearchResults] =
|
|
37
|
-
const [searchTerm, setSearchTerm] =
|
|
38
|
-
const [activeDescendant] =
|
|
36
|
+
const [isSearchOpen, setIsSearchOpen] = useState(false)
|
|
37
|
+
const [isSearchResultOpen, setIsSearchResultOpen] = useState(false)
|
|
38
|
+
const [searchResults, setSearchResults] = useState<SearchResults[] | undefined>()
|
|
39
|
+
const [searchTerm, setSearchTerm] = useState<string | undefined>('')
|
|
40
|
+
const [activeDescendant] = useState<number>(-1)
|
|
39
41
|
|
|
40
42
|
useEffect(() => {
|
|
41
43
|
if (isSearchOpen && inputRef.current) {
|
|
@@ -80,10 +82,10 @@ export function Header({pageMap, docsDirectories, siteTitle}: HeaderProps) {
|
|
|
80
82
|
() =>
|
|
81
83
|
pageMap
|
|
82
84
|
.map(item => {
|
|
83
|
-
if (item
|
|
84
|
-
return item.children.filter(child => child
|
|
85
|
+
if (hasChildren(item)) {
|
|
86
|
+
return (item as Folder).children.filter(child => !hasChildren(child))
|
|
85
87
|
}
|
|
86
|
-
if (item.
|
|
88
|
+
if ((item as DocsItem).type === 'doc') {
|
|
87
89
|
return item
|
|
88
90
|
}
|
|
89
91
|
})
|
|
@@ -1,33 +1,21 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import {Heading, Stack, Text} from '@primer/react-brand'
|
|
3
|
-
import {Folder, MdxFile} from 'nextra'
|
|
4
3
|
|
|
5
4
|
import Link from 'next/link'
|
|
6
5
|
import styles from './IndexCards.module.css'
|
|
6
|
+
import {DocsItem} from '../../../types'
|
|
7
7
|
|
|
8
8
|
type IndexCardsProps = {
|
|
9
9
|
route: string
|
|
10
10
|
folderData: DocsItem[]
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
type FolderWithoutChildren = Omit<Folder, 'children'>
|
|
14
|
-
|
|
15
|
-
type DocsItem = (MdxFile | FolderWithoutChildren) & {
|
|
16
|
-
title: string
|
|
17
|
-
type: string
|
|
18
|
-
children?: DocsItem[]
|
|
19
|
-
firstChildRoute?: string
|
|
20
|
-
withIndexPage?: boolean
|
|
21
|
-
isUnderCurrentDocsTree?: boolean
|
|
22
|
-
}
|
|
23
|
-
|
|
24
13
|
export function IndexCards({route, folderData}: IndexCardsProps) {
|
|
25
|
-
const filteredData = folderData.filter(item => item.
|
|
26
|
-
|
|
14
|
+
const filteredData = folderData.filter(item => item.type === 'doc' && item.route.includes(`${route}/`))
|
|
27
15
|
return (
|
|
28
16
|
<Stack direction="vertical" padding="none" gap="spacious">
|
|
29
17
|
{filteredData.map((item: DocsItem) => {
|
|
30
|
-
if (item.
|
|
18
|
+
if (item.type !== 'doc' || !item.frontMatter) return null
|
|
31
19
|
|
|
32
20
|
return (
|
|
33
21
|
<Stack direction="vertical" padding="none" gap="condensed" key={item.frontMatter.title}>
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {useCallback, useEffect, useMemo, useState} from 'react'
|
|
2
2
|
import debounce from 'lodash.debounce'
|
|
3
3
|
|
|
4
4
|
export function useNavDrawerState(breakpoint): [boolean, (value: boolean) => void] {
|
|
5
5
|
if (typeof breakpoint === 'string') {
|
|
6
6
|
breakpoint = parseInt(breakpoint, 10)
|
|
7
7
|
}
|
|
8
|
-
const [isOpen, setOpen] =
|
|
8
|
+
const [isOpen, setOpen] = useState<boolean>(false)
|
|
9
9
|
|
|
10
|
-
const onResize =
|
|
10
|
+
const onResize = useCallback(() => {
|
|
11
11
|
if (window.innerWidth >= breakpoint) {
|
|
12
12
|
setOpen(false)
|
|
13
13
|
}
|
|
14
14
|
}, [setOpen, breakpoint])
|
|
15
15
|
|
|
16
|
-
const handleSetOpen =
|
|
16
|
+
const handleSetOpen = useCallback(
|
|
17
17
|
(value: boolean) => {
|
|
18
18
|
setOpen(value)
|
|
19
19
|
},
|
|
20
20
|
[setOpen],
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
-
const debouncedOnResize =
|
|
23
|
+
const debouncedOnResize = useMemo(() => debounce(onResize, 250), [onResize])
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
useEffect(() => {
|
|
26
26
|
if (isOpen) {
|
|
27
27
|
// eslint-disable-next-line github/prefer-observers
|
|
28
28
|
window.addEventListener('resize', debouncedOnResize)
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
3
|
-
import {Text, Heading, UnorderedList, InlineLink} from '@primer/react-brand'
|
|
2
|
+
import {Heading, UnorderedList, InlineLink} from '@primer/react-brand'
|
|
4
3
|
import {MdxFile} from 'nextra'
|
|
5
4
|
|
|
6
5
|
import styles from './RelatedContentLinks.module.css'
|
|
7
|
-
import Link from 'next/link'
|
|
8
6
|
import {LinkExternalIcon} from '@primer/octicons-react'
|
|
9
7
|
|
|
10
8
|
export type RelatedContentLink = MdxFile & {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, {useMemo} from 'react'
|
|
1
|
+
import React, {useMemo, useRef} from 'react'
|
|
2
|
+
import {createPortal} from 'react-dom'
|
|
2
3
|
import NextLink from 'next/link'
|
|
3
4
|
import Head from 'next/head'
|
|
4
5
|
import type {Folder, MdxFile, NextraThemeLayoutProps} from 'nextra'
|
|
@@ -34,36 +35,33 @@ import {TableOfContents} from '../table-of-contents/TableOfContents'
|
|
|
34
35
|
import bodyStyles from '../../../css/prose.module.css'
|
|
35
36
|
import {IndexCards} from '../index-cards/IndexCards'
|
|
36
37
|
import {useColorMode} from '../../context/color-modes/useColorMode'
|
|
37
|
-
import {getComponents} from '../../mdx-components/mdx-components'
|
|
38
38
|
import {SkipToMainContent} from '../skip-to-main-content/SkipToMainContent'
|
|
39
39
|
import {RelatedContentLink, RelatedContentLinks} from '../related-content-links/RelatedContentLinks'
|
|
40
|
+
import {hasChildren} from '../../../helpers/hasChildren'
|
|
40
41
|
|
|
41
42
|
const {publicRuntimeConfig} = getConfig()
|
|
42
43
|
|
|
43
44
|
export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
44
|
-
const
|
|
45
|
-
const {
|
|
45
|
+
const tocPortalRef = useRef<HTMLDivElement | null>(null)
|
|
46
|
+
const {title, frontMatter, filePath, pageMap} = pageOpts
|
|
47
|
+
|
|
48
|
+
const {asPath: route} = useRouter()
|
|
46
49
|
const fsPath = useFSRoute()
|
|
47
50
|
const {colorMode} = useColorMode()
|
|
48
51
|
const {activePath, topLevelNavbarItems, docsDirectories, flatDocsDirectories} = useMemo(
|
|
49
52
|
() =>
|
|
50
53
|
normalizePages({
|
|
51
54
|
list: pageMap,
|
|
52
|
-
locale,
|
|
53
|
-
defaultLocale,
|
|
54
55
|
route: fsPath,
|
|
55
56
|
}),
|
|
56
|
-
[pageMap,
|
|
57
|
+
[pageMap, fsPath],
|
|
57
58
|
)
|
|
58
59
|
|
|
59
60
|
const {siteTitle} = publicRuntimeConfig
|
|
60
61
|
const isHomePage = route === '/'
|
|
61
62
|
const isIndexPage = /index\.mdx?$/.test(filePath) && !isHomePage && !frontMatter['show-tabs']
|
|
62
63
|
const data = !isHomePage && activePath[activePath.length - 2]
|
|
63
|
-
const filteredTabData: MdxFile[] =
|
|
64
|
-
data && data.kind === 'Folder'
|
|
65
|
-
? ((data as Folder).children.filter(child => child.kind === 'MdxPage') as MdxFile[])
|
|
66
|
-
: []
|
|
64
|
+
const filteredTabData: MdxFile[] = data && hasChildren(data) ? ((data as Folder).children as MdxFile[]) : []
|
|
67
65
|
|
|
68
66
|
/**
|
|
69
67
|
* Uses a frontmatter 'keywords' value (as an array)
|
|
@@ -165,133 +163,152 @@ export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
|
165
163
|
<PageLayout.Content padding="normal">
|
|
166
164
|
<div id="main">
|
|
167
165
|
<PRCBox sx={!isHomePage && {display: 'flex', maxWidth: 1600, margin: '0 auto'}}>
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
166
|
+
<MDXProvider
|
|
167
|
+
components={{
|
|
168
|
+
wrapper: ({children: mdxChildren, toc}) => {
|
|
169
|
+
return (
|
|
170
|
+
<>
|
|
171
|
+
{tocPortalRef.current &&
|
|
172
|
+
createPortal(
|
|
173
|
+
<PRCBox sx={{py: 2, pr: 3, display: ['none', null, null, null, 'block']}}>
|
|
174
|
+
<PRCBox
|
|
175
|
+
sx={{
|
|
176
|
+
position: 'sticky',
|
|
177
|
+
top: 112,
|
|
178
|
+
width: 220,
|
|
179
|
+
}}
|
|
180
|
+
>
|
|
181
|
+
{toc.length > 0 && <TableOfContents headings={toc} />}
|
|
182
|
+
</PRCBox>
|
|
183
|
+
</PRCBox>,
|
|
184
|
+
|
|
185
|
+
tocPortalRef.current,
|
|
184
186
|
)}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
|
|
188
|
+
<div>{mdxChildren}</div>
|
|
189
|
+
</>
|
|
190
|
+
)
|
|
191
|
+
},
|
|
192
|
+
}}
|
|
193
|
+
>
|
|
194
|
+
<PRCBox sx={!isHomePage && {maxWidth: 800, width: '100%', margin: '0 auto'}}>
|
|
195
|
+
<Stack direction="vertical" padding="none" gap="spacious">
|
|
196
|
+
{!isHomePage && (
|
|
197
|
+
<>
|
|
198
|
+
{activePath.length && (
|
|
199
|
+
<Breadcrumbs>
|
|
200
|
+
{siteTitle && (
|
|
187
201
|
<Breadcrumbs.Item
|
|
188
202
|
as={NextLink}
|
|
189
|
-
|
|
190
|
-
href={item.route}
|
|
191
|
-
selected={index === activePath.length - 1}
|
|
203
|
+
href="/"
|
|
192
204
|
sx={{
|
|
193
|
-
textTransform: 'capitalize',
|
|
194
205
|
color: 'var(--brand-InlineLink-color-rest)',
|
|
195
206
|
}}
|
|
196
207
|
>
|
|
197
|
-
{
|
|
208
|
+
{siteTitle}
|
|
198
209
|
</Breadcrumbs.Item>
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
210
|
+
)}
|
|
211
|
+
{activePath.map((item, index) => {
|
|
212
|
+
return (
|
|
213
|
+
<Breadcrumbs.Item
|
|
214
|
+
as={NextLink}
|
|
215
|
+
key={item.name}
|
|
216
|
+
href={item.route}
|
|
217
|
+
selected={index === activePath.length - 1}
|
|
218
|
+
sx={{
|
|
219
|
+
textTransform: 'capitalize',
|
|
220
|
+
color: 'var(--brand-InlineLink-color-rest)',
|
|
221
|
+
}}
|
|
222
|
+
>
|
|
223
|
+
{item.title.replace(/-/g, ' ')}
|
|
224
|
+
</Breadcrumbs.Item>
|
|
225
|
+
)
|
|
226
|
+
})}
|
|
227
|
+
</Breadcrumbs>
|
|
228
|
+
)}
|
|
203
229
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
</Button>
|
|
227
|
-
{frontMatter['action-2-text'] && (
|
|
228
|
-
<Button as="a" variant="secondary" href={frontMatter['action-2-link']}>
|
|
229
|
-
{frontMatter['action-2-text']}
|
|
230
|
+
<Box>
|
|
231
|
+
<Stack direction="vertical" padding="none" gap={12} alignItems="flex-start">
|
|
232
|
+
{frontMatter.title && (
|
|
233
|
+
<Heading as="h1" size="3">
|
|
234
|
+
{frontMatter.title}
|
|
235
|
+
</Heading>
|
|
236
|
+
)}
|
|
237
|
+
{frontMatter.description && (
|
|
238
|
+
<Text as="p" variant="muted" size="300">
|
|
239
|
+
{frontMatter.description}
|
|
240
|
+
</Text>
|
|
241
|
+
)}
|
|
242
|
+
{frontMatter.image && (
|
|
243
|
+
<Box paddingBlockStart={16}>
|
|
244
|
+
<Hero.Image src={frontMatter.image} alt={frontMatter['image-alt']} />
|
|
245
|
+
</Box>
|
|
246
|
+
)}
|
|
247
|
+
{frontMatter['action-1-text'] && (
|
|
248
|
+
<Box paddingBlockStart={16}>
|
|
249
|
+
<ButtonGroup>
|
|
250
|
+
<Button as="a" href={frontMatter['action-1-link']}>
|
|
251
|
+
{frontMatter['action-1-text']}
|
|
230
252
|
</Button>
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
<IndexCards folderData={flatDocsDirectories} route={route} />
|
|
243
|
-
) : (
|
|
244
|
-
<>
|
|
245
|
-
<MDXProvider components={getComponents()}>{children}</MDXProvider>
|
|
246
|
-
{getRelatedPages().length > 0 && (
|
|
247
|
-
<PRCBox sx={{pt: 5}}>
|
|
248
|
-
<RelatedContentLinks links={getRelatedPages()} />
|
|
249
|
-
</PRCBox>
|
|
250
|
-
)}
|
|
253
|
+
{frontMatter['action-2-text'] && (
|
|
254
|
+
<Button as="a" variant="secondary" href={frontMatter['action-2-link']}>
|
|
255
|
+
{frontMatter['action-2-text']}
|
|
256
|
+
</Button>
|
|
257
|
+
)}
|
|
258
|
+
</ButtonGroup>
|
|
259
|
+
</Box>
|
|
260
|
+
)}
|
|
261
|
+
</Stack>
|
|
262
|
+
</Box>
|
|
263
|
+
{Boolean(frontMatter['show-tabs']) && <UnderlineNav tabData={filteredTabData} />}
|
|
251
264
|
</>
|
|
252
265
|
)}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
266
|
+
<article className={route !== '/' && !isIndexPage ? bodyStyles.Prose : ''}>
|
|
267
|
+
{isIndexPage ? (
|
|
268
|
+
<IndexCards folderData={flatDocsDirectories} route={route} />
|
|
269
|
+
) : (
|
|
270
|
+
<>
|
|
271
|
+
<>{children}</>
|
|
272
|
+
{getRelatedPages().length > 0 && (
|
|
273
|
+
<PRCBox sx={{pt: 5}}>
|
|
274
|
+
<RelatedContentLinks links={getRelatedPages()} />
|
|
275
|
+
</PRCBox>
|
|
276
|
+
)}
|
|
277
|
+
</>
|
|
278
|
+
)}
|
|
279
|
+
</article>
|
|
280
|
+
<footer>
|
|
281
|
+
<Box marginBlockStart={64}>
|
|
282
|
+
<Stack direction="vertical" padding="none" gap={16}>
|
|
283
|
+
<Stack direction="horizontal" padding="none" alignItems="center" gap={8}>
|
|
284
|
+
<PencilIcon size={16} fill="var(--brand-InlineLink-color-rest)" />
|
|
259
285
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
286
|
+
<InlineLink
|
|
287
|
+
href={`${publicRuntimeConfig.repo}/blob/main/${
|
|
288
|
+
publicRuntimeConfig.repoSrcPath ? `${publicRuntimeConfig.repoSrcPath}/` : ''
|
|
289
|
+
}${filePath}`}
|
|
290
|
+
>
|
|
291
|
+
Edit this page
|
|
292
|
+
</InlineLink>
|
|
293
|
+
</Stack>
|
|
294
|
+
<Box
|
|
295
|
+
marginBlockStart={8}
|
|
296
|
+
paddingBlockStart={24}
|
|
297
|
+
borderStyle="solid"
|
|
298
|
+
borderBlockStartWidth="thin"
|
|
299
|
+
borderColor="default"
|
|
264
300
|
>
|
|
265
|
-
|
|
266
|
-
|
|
301
|
+
<Text as="p" variant="muted" size="100">
|
|
302
|
+
© {new Date().getFullYear()} GitHub, Inc. All rights reserved.
|
|
303
|
+
</Text>
|
|
304
|
+
</Box>
|
|
267
305
|
</Stack>
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
borderStyle="solid"
|
|
272
|
-
borderBlockStartWidth="thin"
|
|
273
|
-
borderColor="default"
|
|
274
|
-
>
|
|
275
|
-
<Text as="p" variant="muted" size="100">
|
|
276
|
-
© {new Date().getFullYear()} GitHub, Inc. All rights reserved.
|
|
277
|
-
</Text>
|
|
278
|
-
</Box>
|
|
279
|
-
</Stack>
|
|
280
|
-
</Box>
|
|
281
|
-
</footer>
|
|
282
|
-
</Stack>
|
|
283
|
-
</PRCBox>
|
|
284
|
-
<PRCBox sx={{py: 2, pr: 3, display: ['none', null, null, null, 'block']}}>
|
|
285
|
-
<PRCBox
|
|
286
|
-
sx={{
|
|
287
|
-
position: 'sticky',
|
|
288
|
-
top: 112,
|
|
289
|
-
width: 220,
|
|
290
|
-
}}
|
|
291
|
-
>
|
|
292
|
-
{!isHomePage && headings.length > 0 && <TableOfContents headings={headings} />}
|
|
306
|
+
</Box>
|
|
307
|
+
</footer>
|
|
308
|
+
</Stack>
|
|
293
309
|
</PRCBox>
|
|
294
|
-
</
|
|
310
|
+
</MDXProvider>
|
|
311
|
+
<div ref={tocPortalRef} />
|
|
295
312
|
</PRCBox>
|
|
296
313
|
</div>
|
|
297
314
|
</PageLayout.Content>
|
|
@@ -315,3 +332,22 @@ export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
|
315
332
|
</>
|
|
316
333
|
)
|
|
317
334
|
}
|
|
335
|
+
|
|
336
|
+
export function MdxWrapper({children, toc}) {
|
|
337
|
+
return (
|
|
338
|
+
<>
|
|
339
|
+
<PRCBox sx={{py: 2, pr: 3, display: ['none', null, null, null, 'block']}}>
|
|
340
|
+
<PRCBox
|
|
341
|
+
sx={{
|
|
342
|
+
position: 'sticky',
|
|
343
|
+
top: 112,
|
|
344
|
+
width: 220,
|
|
345
|
+
}}
|
|
346
|
+
>
|
|
347
|
+
{toc.length > 0 && <TableOfContents headings={toc} />}
|
|
348
|
+
</PRCBox>
|
|
349
|
+
</PRCBox>
|
|
350
|
+
<div>{children}</div>
|
|
351
|
+
</>
|
|
352
|
+
)
|
|
353
|
+
}
|
|
@@ -1,31 +1,25 @@
|
|
|
1
1
|
import React, {useMemo} from 'react'
|
|
2
2
|
import NextLink from 'next/link'
|
|
3
3
|
import {NavList} from '@primer/react'
|
|
4
|
-
import {Folder, MdxFile
|
|
4
|
+
import {Folder, MdxFile} from 'nextra'
|
|
5
5
|
import {useRouter} from 'next/router'
|
|
6
6
|
import getConfig from 'next/config'
|
|
7
7
|
|
|
8
8
|
import styles from './Sidebar.module.css'
|
|
9
9
|
import {LinkExternalIcon} from '@primer/octicons-react'
|
|
10
|
-
import type {ThemeConfig} from '../../../index'
|
|
10
|
+
import type {DocsItem, ThemeConfig} from '../../../index'
|
|
11
|
+
import {hasChildren} from '../../../helpers/hasChildren'
|
|
11
12
|
|
|
12
13
|
type SidebarProps = {
|
|
13
14
|
pageMap: DocsItem[]
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
const {publicRuntimeConfig} = getConfig()
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
type: string
|
|
21
|
-
children?: DocsItem[]
|
|
22
|
-
firstChildRoute?: string
|
|
23
|
-
withIndexPage?: boolean
|
|
24
|
-
isUnderCurrentDocsTree?: boolean
|
|
19
|
+
const hasShowTabs = (child: DocsItem): boolean => {
|
|
20
|
+
return child.name === 'index' && (child as MdxFile).frontMatter?.['show-tabs'] === true
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
const {publicRuntimeConfig} = getConfig()
|
|
28
|
-
|
|
29
23
|
export function Sidebar({pageMap}: SidebarProps) {
|
|
30
24
|
const router = useRouter()
|
|
31
25
|
|
|
@@ -39,11 +33,11 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
39
33
|
const reorderedPageMap = useMemo(
|
|
40
34
|
() =>
|
|
41
35
|
[...pageMap].sort((a, b) => {
|
|
42
|
-
if (a
|
|
43
|
-
const aIndex = a.children.find(child => child.name === 'index' && child.
|
|
36
|
+
if (hasChildren(a) && a.children) {
|
|
37
|
+
const aIndex = a.children.find(child => child.name === 'index' && child.type === 'doc')
|
|
44
38
|
const aPosition = (aIndex as MdxFile | undefined)?.frontMatter?.['menu-position'] ?? Infinity
|
|
45
|
-
if (b
|
|
46
|
-
const bIndex = b.children.find(child => child.name === 'index' && child.
|
|
39
|
+
if (hasChildren(b) && b.children) {
|
|
40
|
+
const bIndex = b.children.find(child => child.name === 'index' && child.type === 'doc')
|
|
47
41
|
const bPosition = (bIndex as MdxFile | undefined)?.frontMatter?.['menu-position'] ?? Infinity
|
|
48
42
|
return aPosition - bPosition
|
|
49
43
|
}
|
|
@@ -57,21 +51,19 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
57
51
|
<div className={styles.Sidebar}>
|
|
58
52
|
<NavList className={styles.NavList} aria-label="Menu links">
|
|
59
53
|
{reorderedPageMap.map(item => {
|
|
60
|
-
if (item.
|
|
54
|
+
if (item.type === 'doc' && item.route === '/') return null
|
|
61
55
|
|
|
62
|
-
if (item.
|
|
56
|
+
if (!hasChildren(item) && item.type === 'doc') {
|
|
63
57
|
return (
|
|
64
58
|
<NavList.Item as={NextLink} key={item.name} href={item.route} sx={{textTransform: 'capitalize'}}>
|
|
65
|
-
{item.frontMatter?.title ?? item.name}
|
|
59
|
+
{(item as MdxFile).frontMatter?.title ?? item.name}
|
|
66
60
|
</NavList.Item>
|
|
67
61
|
)
|
|
68
62
|
}
|
|
69
63
|
|
|
70
64
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
71
|
-
if (item
|
|
72
|
-
const indexPage = (item as Folder).children.find(
|
|
73
|
-
child => child.kind === 'MdxPage' && child.name === 'index',
|
|
74
|
-
) as MdxFile
|
|
65
|
+
if (hasChildren(item)) {
|
|
66
|
+
const indexPage = (item as Folder).children.find(child => (child as MdxFile).name === 'index') as MdxFile
|
|
75
67
|
const subNavName = indexPage.frontMatter?.title ?? ''
|
|
76
68
|
const shouldShowTabs = indexPage.frontMatter?.['show-tabs'] ?? false
|
|
77
69
|
if (shouldShowTabs) {
|
|
@@ -87,28 +79,27 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
87
79
|
{item.children &&
|
|
88
80
|
item.children
|
|
89
81
|
.sort((a, b) => (a.name === 'index' ? -1 : b.name === 'index' ? 1 : 0)) // puts index page first
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
(child as DocsItem).name !== 'index' ||
|
|
93
|
-
((child.name === 'index' && (child as MdxFile).frontMatter?.['show-tabs']) ?? false),
|
|
94
|
-
) // only show index page if it has show-tabs
|
|
82
|
+
// only show index page if it has show-tabs
|
|
83
|
+
.filter(child => child.name !== 'index' || hasShowTabs(child))
|
|
95
84
|
.map((child: DocsItem) => {
|
|
96
|
-
if (child.
|
|
85
|
+
if (child.type === 'doc') {
|
|
97
86
|
return (
|
|
98
87
|
<NavList.Item
|
|
99
88
|
as={NextLink}
|
|
100
89
|
key={child.name}
|
|
101
90
|
href={child.route}
|
|
91
|
+
sx={{textTransform: 'capitalize'}}
|
|
102
92
|
aria-current={child.route === router.pathname ? 'page' : undefined}
|
|
103
93
|
>
|
|
104
|
-
{
|
|
94
|
+
{child.title}
|
|
105
95
|
</NavList.Item>
|
|
106
96
|
)
|
|
107
97
|
}
|
|
108
98
|
|
|
109
|
-
if ((child
|
|
110
|
-
const landingPageItem
|
|
111
|
-
innerChild =>
|
|
99
|
+
if (hasChildren(child)) {
|
|
100
|
+
const landingPageItem = (child as Folder).children.find(
|
|
101
|
+
innerChild =>
|
|
102
|
+
(innerChild as DocsItem).type === 'doc' && (innerChild as DocsItem).name === 'index',
|
|
112
103
|
)
|
|
113
104
|
return (
|
|
114
105
|
<NavList.Item
|
package/css/global.css
CHANGED
|
@@ -14,100 +14,6 @@ body {
|
|
|
14
14
|
margin-block-start: 0 !important;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* Code block overrides
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
:root {
|
|
22
|
-
--shiki-color-text: #414141;
|
|
23
|
-
--shiki-color-background: transparent;
|
|
24
|
-
--shiki-token-constant: #1976d2;
|
|
25
|
-
--shiki-token-string: #22863a;
|
|
26
|
-
--shiki-token-comment: #aaa;
|
|
27
|
-
--shiki-token-keyword: #d32f2f;
|
|
28
|
-
--shiki-token-parameter: #ff9801;
|
|
29
|
-
--shiki-token-function: #6f42c1;
|
|
30
|
-
--shiki-token-string-expression: var(--shiki-token-string);
|
|
31
|
-
--shiki-token-punctuation: #212121;
|
|
32
|
-
--shiki-token-link: var(--shiki-token-string);
|
|
33
|
-
--shiki-color-ansi-black: #24292e;
|
|
34
|
-
--shiki-color-ansi-black-dim: rgba(36, 41, 46, 0.5);
|
|
35
|
-
--shiki-color-ansi-red: #d73a49;
|
|
36
|
-
--shiki-color-ansi-red-dim: rgba(215, 58, 73, 0.5);
|
|
37
|
-
--shiki-color-ansi-green: #28a745;
|
|
38
|
-
--shiki-color-ansi-green-dim: rgba(40, 167, 69, 0.5);
|
|
39
|
-
--shiki-color-ansi-yellow: #dbab09;
|
|
40
|
-
--shiki-color-ansi-yellow-dim: rgba(219, 171, 9, 0.5);
|
|
41
|
-
--shiki-color-ansi-blue: #0366d6;
|
|
42
|
-
--shiki-color-ansi-blue-dim: rgba(3, 102, 214, 0.5);
|
|
43
|
-
--shiki-color-ansi-magenta: #5a32a3;
|
|
44
|
-
--shiki-color-ansi-magenta-dim: rgba(90, 50, 163, 0.5);
|
|
45
|
-
--shiki-color-ansi-cyan: #1b7c83;
|
|
46
|
-
--shiki-color-ansi-cyan-dim: rgba(27, 124, 131, 0.5);
|
|
47
|
-
--shiki-color-ansi-white: #6a737d;
|
|
48
|
-
--shiki-color-ansi-white-dim: rgba(106, 115, 125, 0.5);
|
|
49
|
-
--shiki-color-ansi-bright-black: #959da5;
|
|
50
|
-
--shiki-color-ansi-bright-black-dim: rgba(149, 157, 165, 0.5);
|
|
51
|
-
--shiki-color-ansi-bright-red: #cb2431;
|
|
52
|
-
--shiki-color-ansi-bright-red-dim: rgba(203, 36, 49, 0.5);
|
|
53
|
-
--shiki-color-ansi-bright-green: #22863a;
|
|
54
|
-
--shiki-color-ansi-bright-green-dim: rgba(34, 134, 58, 0.5);
|
|
55
|
-
--shiki-color-ansi-bright-yellow: #b08800;
|
|
56
|
-
--shiki-color-ansi-bright-yellow-dim: rgba(176, 136, 0, 0.5);
|
|
57
|
-
--shiki-color-ansi-bright-blue: #005cc5;
|
|
58
|
-
--shiki-color-ansi-bright-blue-dim: rgba(0, 92, 197, 0.5);
|
|
59
|
-
--shiki-color-ansi-bright-magenta: #5a32a3;
|
|
60
|
-
--shiki-color-ansi-bright-magenta-dim: rgba(90, 50, 163, 0.5);
|
|
61
|
-
--shiki-color-ansi-bright-cyan: #3192aa;
|
|
62
|
-
--shiki-color-ansi-bright-cyan-dim: rgba(49, 146, 170, 0.5);
|
|
63
|
-
--shiki-color-ansi-bright-white: #d1d5da;
|
|
64
|
-
--shiki-color-ansi-bright-white-dim: rgba(209, 213, 218, 0.5);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
[data-color-mode='dark'] {
|
|
68
|
-
--shiki-color-text: #d1d1d1;
|
|
69
|
-
--shiki-token-constant: #79b8ff;
|
|
70
|
-
--shiki-token-string: #ffab70;
|
|
71
|
-
--shiki-token-comment: #6b737c;
|
|
72
|
-
--shiki-token-keyword: #f97583;
|
|
73
|
-
--shiki-token-function: #b392f0;
|
|
74
|
-
--shiki-token-string-expression: #4bb74a;
|
|
75
|
-
--shiki-token-punctuation: #bbb;
|
|
76
|
-
--shiki-token-link: var(--shiki-token-string);
|
|
77
|
-
--shiki-color-ansi-black: #586069;
|
|
78
|
-
--shiki-color-ansi-black-dim: rgba(88, 96, 105, 0.5);
|
|
79
|
-
--shiki-color-ansi-red: #ea4a5a;
|
|
80
|
-
--shiki-color-ansi-red-dim: rgba(234, 74, 90, 0.5);
|
|
81
|
-
--shiki-color-ansi-green: #34d058;
|
|
82
|
-
--shiki-color-ansi-green-dim: rgba(52, 208, 88, 0.5);
|
|
83
|
-
--shiki-color-ansi-yellow: #ffea7f;
|
|
84
|
-
--shiki-color-ansi-yellow-dim: rgba(255, 234, 127, 0.5);
|
|
85
|
-
--shiki-color-ansi-blue: #2188ff;
|
|
86
|
-
--shiki-color-ansi-blue-dim: rgba(33, 136, 255, 0.5);
|
|
87
|
-
--shiki-color-ansi-magenta: #b392f0;
|
|
88
|
-
--shiki-color-ansi-magenta-dim: rgba(179, 146, 240, 0.5);
|
|
89
|
-
--shiki-color-ansi-cyan: #39c5cf;
|
|
90
|
-
--shiki-color-ansi-cyan-dim: rgba(57, 197, 207, 0.5);
|
|
91
|
-
--shiki-color-ansi-white: #d1d5da;
|
|
92
|
-
--shiki-color-ansi-white-dim: rgba(209, 213, 218, 0.5);
|
|
93
|
-
--shiki-color-ansi-bright-black: #959da5;
|
|
94
|
-
--shiki-color-ansi-bright-black-dim: rgba(149, 157, 165, 0.5);
|
|
95
|
-
--shiki-color-ansi-bright-red: #f97583;
|
|
96
|
-
--shiki-color-ansi-bright-red-dim: rgba(249, 117, 131, 0.5);
|
|
97
|
-
--shiki-color-ansi-bright-green: #85e89d;
|
|
98
|
-
--shiki-color-ansi-bright-green-dim: rgba(133, 232, 157, 0.5);
|
|
99
|
-
--shiki-color-ansi-bright-yellow: #ffea7f;
|
|
100
|
-
--shiki-color-ansi-bright-yellow-dim: rgba(255, 234, 127, 0.5);
|
|
101
|
-
--shiki-color-ansi-bright-blue: #79b8ff;
|
|
102
|
-
--shiki-color-ansi-bright-blue-dim: rgba(121, 184, 255, 0.5);
|
|
103
|
-
--shiki-color-ansi-bright-magenta: #b392f0;
|
|
104
|
-
--shiki-color-ansi-bright-magenta-dim: rgba(179, 146, 240, 0.5);
|
|
105
|
-
--shiki-color-ansi-bright-cyan: #56d4dd;
|
|
106
|
-
--shiki-color-ansi-bright-cyan-dim: rgba(86, 212, 221, 0.5);
|
|
107
|
-
--shiki-color-ansi-bright-white: #fafbfc;
|
|
108
|
-
--shiki-color-ansi-bright-white-dim: rgba(250, 251, 252, 0.5);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
17
|
pre {
|
|
112
18
|
background-color: var(--brand-color-canvas-subtle);
|
|
113
19
|
border-radius: var(--brand-borderRadius-large);
|
|
@@ -123,6 +29,15 @@ code {
|
|
|
123
29
|
'calt' 1,
|
|
124
30
|
'ss01' 1;
|
|
125
31
|
}
|
|
32
|
+
|
|
33
|
+
code span {
|
|
34
|
+
color: var(--shiki-light);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[data-color-mode='dark'] code span {
|
|
38
|
+
color: var(--shiki-dark);
|
|
39
|
+
}
|
|
40
|
+
|
|
126
41
|
code[data-line-numbers] > .line {
|
|
127
42
|
padding-left: 0.5rem;
|
|
128
43
|
}
|
package/doctocat.config.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import nextra from 'nextra'
|
|
2
|
+
import transpiler from 'next-transpile-modules'
|
|
3
|
+
|
|
4
|
+
const withNextra = nextra({
|
|
2
5
|
theme: '@primer/doctocat-nextjs',
|
|
3
6
|
staticImage: true,
|
|
4
7
|
})
|
|
5
8
|
|
|
6
|
-
const withTM =
|
|
9
|
+
const withTM = transpiler(['@primer/doctocat-nextjs'])
|
|
7
10
|
|
|
8
11
|
/*
|
|
9
12
|
* Wrapper for next config, that allows us to do some shared configuration
|
|
@@ -23,4 +26,4 @@ function withDoctocat(config = {}) {
|
|
|
23
26
|
})
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
export default withDoctocat
|
package/package.json
CHANGED
|
@@ -1,37 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/doctocat-nextjs",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "A Next.js theme for building Primer documentation sites",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
+
"check": "tsc --noEmit",
|
|
9
|
+
"lint": "eslint '**/*.{js,ts,tsx,md,mdx}' --max-warnings=0 --config ./.eslintrc.cjs",
|
|
8
10
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
11
|
},
|
|
10
12
|
"author": "GitHub, Inc.",
|
|
11
13
|
"license": "MIT",
|
|
12
14
|
"peerDependencies": {
|
|
13
|
-
"next": "
|
|
14
|
-
"react": "
|
|
15
|
-
"react-dom": "
|
|
15
|
+
"next": "15.1.6",
|
|
16
|
+
"react": "18.3.1",
|
|
17
|
+
"react-dom": "18.3.1"
|
|
16
18
|
},
|
|
17
19
|
"dependencies": {
|
|
18
|
-
"@primer/octicons-react": "
|
|
19
|
-
"@primer/react": "
|
|
20
|
-
"@primer/react-brand": "
|
|
20
|
+
"@primer/octicons-react": "19.14.0",
|
|
21
|
+
"@primer/react": "36.27.0",
|
|
22
|
+
"@primer/react-brand": "0.46.0",
|
|
21
23
|
"next-transpile-modules": "^10.0.1",
|
|
22
|
-
"framer-motion": "
|
|
24
|
+
"framer-motion": "12.0.1",
|
|
23
25
|
"lodash.debounce": "^4.0.8",
|
|
24
|
-
"react-focus-on": "
|
|
25
|
-
"nextra": "
|
|
26
|
+
"react-focus-on": "3.9.4",
|
|
27
|
+
"nextra": "3.3.1",
|
|
28
|
+
"react": "18.3.1",
|
|
29
|
+
"react-dom": "18.3.1"
|
|
26
30
|
},
|
|
27
31
|
"devDependencies": {
|
|
28
32
|
"@github/prettier-config": "^0.0.6",
|
|
29
33
|
"@types/node": "18.11.10",
|
|
30
|
-
"@types/react": "
|
|
31
|
-
"@types/react-dom": "
|
|
32
|
-
"clsx": "
|
|
33
|
-
"next": "
|
|
34
|
-
"styled-components": "
|
|
35
|
-
"typescript": "
|
|
34
|
+
"@types/react": "18.3.12",
|
|
35
|
+
"@types/react-dom": "18.3.1",
|
|
36
|
+
"clsx": "2.1.1",
|
|
37
|
+
"next": "15.1.6",
|
|
38
|
+
"styled-components": "6.1.13",
|
|
39
|
+
"typescript": "5.7.3"
|
|
40
|
+
},
|
|
41
|
+
"overrides": {
|
|
42
|
+
"@types/react": "18.3.12",
|
|
43
|
+
"@types/react-dom": "18.3.1"
|
|
36
44
|
}
|
|
37
45
|
}
|
package/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {Folder, MdxFile} from 'nextra'
|
|
2
|
+
|
|
1
3
|
export type ThemeConfig = {
|
|
2
4
|
docsRepositoryBase: string
|
|
3
5
|
sidebarLinks?: {
|
|
@@ -5,3 +7,14 @@ export type ThemeConfig = {
|
|
|
5
7
|
href: string
|
|
6
8
|
}[]
|
|
7
9
|
}
|
|
10
|
+
|
|
11
|
+
export type FolderWithoutChildren = Omit<Folder, 'children'>
|
|
12
|
+
|
|
13
|
+
export type DocsItem = MdxFile & {
|
|
14
|
+
title: string
|
|
15
|
+
type: string
|
|
16
|
+
children?: DocsItem[]
|
|
17
|
+
firstChildRoute?: string
|
|
18
|
+
withIndexPage?: boolean
|
|
19
|
+
isUnderCurrentDocsTree?: boolean
|
|
20
|
+
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
.Heading__anchor {
|
|
2
|
-
color: var(--brand-color-text-default) !important;
|
|
3
|
-
text-decoration: none !important;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.Heading__anchorIcon {
|
|
7
|
-
visibility: hidden;
|
|
8
|
-
margin-left: var(--base-size-8);
|
|
9
|
-
vertical-align: middle !important;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.Heading__anchor:hover .Heading__anchorIcon {
|
|
13
|
-
visibility: visible;
|
|
14
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import type {ComponentProps, ReactElement} from 'react'
|
|
3
|
-
import clsx from 'clsx'
|
|
4
|
-
import type {Components} from 'nextra/mdx'
|
|
5
|
-
|
|
6
|
-
import {LinkIcon} from '@primer/octicons-react'
|
|
7
|
-
import NextLink from 'next/link'
|
|
8
|
-
|
|
9
|
-
import styles from './mdx-components.module.css'
|
|
10
|
-
|
|
11
|
-
// Anchor links for Headings
|
|
12
|
-
function HeadingLink({
|
|
13
|
-
tag: Tag,
|
|
14
|
-
context,
|
|
15
|
-
children,
|
|
16
|
-
id,
|
|
17
|
-
className,
|
|
18
|
-
...props
|
|
19
|
-
}: ComponentProps<'h2'> & {
|
|
20
|
-
tag: `h${2 | 3 | 4 | 5 | 6}`
|
|
21
|
-
context: {index: number}
|
|
22
|
-
}): ReactElement {
|
|
23
|
-
return (
|
|
24
|
-
<Tag {...props} id={id} className={clsx(className)}>
|
|
25
|
-
<NextLink href={`#${id}`} className={styles.Heading__anchor}>
|
|
26
|
-
{children} <LinkIcon className={styles.Heading__anchorIcon} size={16} />
|
|
27
|
-
</NextLink>
|
|
28
|
-
</Tag>
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const Link = ({href = '', className, ...props}) => <NextLink href={href} {...props} />
|
|
33
|
-
export const getComponents = (): Components => {
|
|
34
|
-
const context = {index: 0}
|
|
35
|
-
return {
|
|
36
|
-
h2: props => <HeadingLink tag="h2" context={context} {...props} />,
|
|
37
|
-
h3: props => <HeadingLink tag="h3" context={context} {...props} />,
|
|
38
|
-
h4: props => <HeadingLink tag="h4" context={context} {...props} />,
|
|
39
|
-
h5: props => <HeadingLink tag="h5" context={context} {...props} />,
|
|
40
|
-
h6: props => <HeadingLink tag="h6" context={context} {...props} />,
|
|
41
|
-
a: Link,
|
|
42
|
-
}
|
|
43
|
-
}
|
|
File without changes
|