@primer/doctocat-nextjs 0.0.2-rc.cdbd6bf → 0.0.2-rc.de031ea
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/CHANGELOG.md +10 -0
- package/components/layout/header/Header.tsx +12 -2
- package/components/layout/index-cards/IndexCards.tsx +9 -8
- package/components/layout/nav-drawer/NavDrawer.tsx +2 -1
- package/components/layout/root-layout/Theme.tsx +22 -10
- package/components/layout/sidebar/Sidebar.tsx +15 -44
- package/components/layout/skip-to-main-content/SkipToMainContent.module.css +17 -0
- package/components/layout/skip-to-main-content/SkipToMainContent.tsx +14 -0
- package/components/layout/table-of-contents/TableOfContents.tsx +6 -4
- package/components/mdx-components/mdx-components.module.css +14 -0
- package/components/mdx-components/mdx-components.tsx +43 -0
- package/css/prose.module.css +2 -5
- package/package.json +1 -1
- package/types.ts +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,4 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
+
- [#4](https://github.com/primer/doctocat-nextjs/pull/4) [`4f28982`](https://github.com/primer/doctocat-nextjs/commit/4f28982e327e75f199f28fad987f1e827deafeb2) Thanks [@joseph-lozano](https://github.com/joseph-lozano)! - Wrap links with Next's Link component
|
|
8
|
+
|
|
9
|
+
- [`6f21970`](https://github.com/primer/doctocat-nextjs/commit/6f21970c74f7635be89fc4cd20376d7fe5ca35e7) Thanks [@rezrah](https://github.com/rezrah)! - Switch hero image order with description and reduce `h2` block start margin
|
|
10
|
+
|
|
11
|
+
- [#6](https://github.com/primer/doctocat-nextjs/pull/6) [`afd4e17`](https://github.com/primer/doctocat-nextjs/commit/afd4e1762f6294a14942d415c693319a874cd3fb) Thanks [@rezrah](https://github.com/rezrah)! - - Add MDX to HTML overrides mechanism and apply to headings and anchors
|
|
12
|
+
|
|
13
|
+
- Added anchor links to headings to match current functionality on primer.style
|
|
14
|
+
|
|
15
|
+
- [`b49f218`](https://github.com/primer/doctocat-nextjs/commit/b49f218e9bbc2de720476e21888956bee6081967) Thanks [@rezrah](https://github.com/rezrah)! - Removed sidebar links and added skip to main content a11y link
|
|
16
|
+
|
|
7
17
|
- [#2](https://github.com/primer/doctocat-nextjs/pull/2) [`2742b32`](https://github.com/primer/doctocat-nextjs/commit/2742b3214e7a53416d23f0459dc389f7c22cf5a1) Thanks [@rezrah](https://github.com/rezrah)! - Remove code blocks stylesheet, now merged into global.css
|
|
@@ -4,7 +4,7 @@ import {Heading, Stack, Text} from '@primer/react-brand'
|
|
|
4
4
|
import clsx from 'clsx'
|
|
5
5
|
import {MdxFile, PageMapItem} from 'nextra'
|
|
6
6
|
import type {PageItem} from 'nextra/normalize-pages'
|
|
7
|
-
import React, {useEffect, useMemo} from 'react'
|
|
7
|
+
import React, {useCallback, useEffect, useMemo} from 'react'
|
|
8
8
|
import {debounce} from 'lodash'
|
|
9
9
|
|
|
10
10
|
import Link from 'next/link'
|
|
@@ -37,6 +37,12 @@ export function Header({pageMap, docsDirectories, siteTitle}: HeaderProps) {
|
|
|
37
37
|
const [searchTerm, setSearchTerm] = React.useState<string | undefined>('')
|
|
38
38
|
const [activeDescendant] = React.useState<number>(-1)
|
|
39
39
|
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (isSearchOpen && inputRef.current) {
|
|
42
|
+
inputRef.current.focus()
|
|
43
|
+
}
|
|
44
|
+
}, [isSearchOpen])
|
|
45
|
+
|
|
40
46
|
useEffect(() => {
|
|
41
47
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
42
48
|
if (event.key === 'Escape') {
|
|
@@ -152,6 +158,10 @@ export function Header({pageMap, docsDirectories, siteTitle}: HeaderProps) {
|
|
|
152
158
|
alert(`Name: ${inputRef.current.value}`)
|
|
153
159
|
}
|
|
154
160
|
|
|
161
|
+
const handleSearchButtonOpenClick = useCallback(() => {
|
|
162
|
+
setIsSearchOpen(true)
|
|
163
|
+
}, [])
|
|
164
|
+
|
|
155
165
|
return (
|
|
156
166
|
<nav className={clsx(styles.Header, isSearchOpen && styles['Header--searchAreaOpen'])}>
|
|
157
167
|
<Link href="/" className={styles.Header__siteTitle}>
|
|
@@ -292,7 +302,7 @@ export function Header({pageMap, docsDirectories, siteTitle}: HeaderProps) {
|
|
|
292
302
|
variant="invisible"
|
|
293
303
|
aria-label={`Open search`}
|
|
294
304
|
sx={{display: ['flex', null, 'none']}}
|
|
295
|
-
onClick={
|
|
305
|
+
onClick={handleSearchButtonOpenClick}
|
|
296
306
|
/>
|
|
297
307
|
<Box sx={{display: ['flex', null, 'none']}}>
|
|
298
308
|
<IconButton
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import {Card, Grid} from '@primer/react-brand'
|
|
3
3
|
import {Folder, MdxFile} from 'nextra'
|
|
4
|
-
import {useRouter} from 'next/router'
|
|
5
4
|
|
|
6
5
|
import styles from './IndexCards.module.css'
|
|
6
|
+
import Link from 'next/link'
|
|
7
7
|
|
|
8
8
|
type IndexCardsProps = {
|
|
9
9
|
route: string
|
|
@@ -22,7 +22,6 @@ type DocsItem = (MdxFile | FolderWithoutChildren) & {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function IndexCards({route, folderData}: IndexCardsProps) {
|
|
25
|
-
const {basePath} = useRouter()
|
|
26
25
|
const filteredData = folderData.filter(item => item.kind === 'MdxPage' && item.route.includes(`${route}/`))
|
|
27
26
|
|
|
28
27
|
return (
|
|
@@ -31,12 +30,14 @@ export function IndexCards({route, folderData}: IndexCardsProps) {
|
|
|
31
30
|
if (item.kind !== 'MdxPage') return null
|
|
32
31
|
return (
|
|
33
32
|
<Grid.Column span={{medium: 6}} key={`cell-${item.route}`}>
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
<Link href={item.route} legacyBehavior passHref>
|
|
34
|
+
<Card href="#" hasBorder style={{width: '100%'}}>
|
|
35
|
+
{item.frontMatter && <Card.Heading>{item.frontMatter.title}</Card.Heading>}
|
|
36
|
+
{item.frontMatter && item.frontMatter.description && (
|
|
37
|
+
<Card.Description>{item.frontMatter.description}</Card.Description>
|
|
38
|
+
)}
|
|
39
|
+
</Card>
|
|
40
|
+
</Link>
|
|
40
41
|
</Grid.Column>
|
|
41
42
|
)
|
|
42
43
|
})}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import NextLink from 'next/link'
|
|
2
3
|
import {Box, IconButton, Link, ThemeProvider} from '@primer/react'
|
|
3
4
|
import {XIcon} from '@primer/octicons-react'
|
|
4
5
|
|
|
@@ -34,7 +35,7 @@ export function NavDrawer({isOpen, onDismiss, navItems}: NavDrawerProps) {
|
|
|
34
35
|
}}
|
|
35
36
|
>
|
|
36
37
|
<Box sx={{py: 20, pl: 4, pr: 3, alignItems: 'center', justifyContent: 'space-between', display: 'flex'}}>
|
|
37
|
-
<Link href="https://primer.style" sx={{fontWeight: 'bold', color: 'inherit'}}>
|
|
38
|
+
<Link as={NextLink} href="https://primer.style" sx={{fontWeight: 'bold', color: 'inherit'}}>
|
|
38
39
|
Explore
|
|
39
40
|
</Link>
|
|
40
41
|
<IconButton icon={XIcon} aria-label="Close" onClick={onDismiss} variant="invisible" />
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React, {useMemo} from 'react'
|
|
2
|
+
import NextLink from 'next/link'
|
|
2
3
|
import Head from 'next/head'
|
|
3
4
|
import type {Folder, MdxFile, NextraThemeLayoutProps} from 'nextra'
|
|
5
|
+
import {MDXProvider} from 'nextra/mdx'
|
|
4
6
|
import {useFSRoute} from 'nextra/hooks'
|
|
5
7
|
import {PencilIcon} from '@primer/octicons-react'
|
|
6
8
|
import {BaseStyles, Box as PRCBox, Breadcrumbs, PageLayout, ThemeProvider} from '@primer/react'
|
|
9
|
+
|
|
7
10
|
import {
|
|
8
11
|
Animate,
|
|
9
12
|
AnimationProvider,
|
|
@@ -31,12 +34,14 @@ import {TableOfContents} from '../table-of-contents/TableOfContents'
|
|
|
31
34
|
import bodyStyles from '../../../css/prose.module.css'
|
|
32
35
|
import {IndexCards} from '../index-cards/IndexCards'
|
|
33
36
|
import {useColorMode} from '../../context/color-modes/useColorMode'
|
|
37
|
+
import {getComponents} from '../../mdx-components/mdx-components'
|
|
38
|
+
import {SkipToMainContent} from '../skip-to-main-content/SkipToMainContent'
|
|
34
39
|
|
|
35
40
|
const {publicRuntimeConfig} = getConfig()
|
|
36
41
|
|
|
37
42
|
export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
38
43
|
const {title, frontMatter, headings, filePath, pageMap, route} = pageOpts
|
|
39
|
-
const {locale = 'en-US', defaultLocale
|
|
44
|
+
const {locale = 'en-US', defaultLocale} = useRouter()
|
|
40
45
|
const fsPath = useFSRoute()
|
|
41
46
|
const {colorMode} = useColorMode()
|
|
42
47
|
const {activePath, topLevelNavbarItems, docsDirectories, flatDocsDirectories} = useMemo(
|
|
@@ -77,6 +82,7 @@ export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
|
77
82
|
zIndex: 99,
|
|
78
83
|
}}
|
|
79
84
|
>
|
|
85
|
+
<SkipToMainContent href="#main">Skip to main content</SkipToMainContent>
|
|
80
86
|
<Header
|
|
81
87
|
pageMap={pageMap}
|
|
82
88
|
docsDirectories={docsDirectories}
|
|
@@ -86,7 +92,7 @@ export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
|
86
92
|
</PRCBox>
|
|
87
93
|
<PageLayout rowGap="none" columnGap="none" padding="none" containerWidth="full">
|
|
88
94
|
<PageLayout.Content padding="normal">
|
|
89
|
-
<main>
|
|
95
|
+
<main id="main">
|
|
90
96
|
<PRCBox sx={!isHomePage && {display: 'flex', maxWidth: 1600, margin: '0 auto'}}>
|
|
91
97
|
<PRCBox sx={!isHomePage && {maxWidth: 800, width: '100%', margin: '0 auto'}}>
|
|
92
98
|
<Stack direction="vertical" padding="none" gap="spacious">
|
|
@@ -96,7 +102,8 @@ export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
|
96
102
|
<Breadcrumbs>
|
|
97
103
|
{siteTitle && (
|
|
98
104
|
<Breadcrumbs.Item
|
|
99
|
-
|
|
105
|
+
as={NextLink}
|
|
106
|
+
href="/"
|
|
100
107
|
sx={{
|
|
101
108
|
color: 'var(--brand-InlineLink-color-rest)',
|
|
102
109
|
}}
|
|
@@ -107,8 +114,9 @@ export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
|
107
114
|
{activePath.map((item, index) => {
|
|
108
115
|
return (
|
|
109
116
|
<Breadcrumbs.Item
|
|
117
|
+
as={NextLink}
|
|
110
118
|
key={item.name}
|
|
111
|
-
href={
|
|
119
|
+
href={item.route}
|
|
112
120
|
selected={index === activePath.length - 1}
|
|
113
121
|
sx={{
|
|
114
122
|
textTransform: 'capitalize',
|
|
@@ -129,16 +137,16 @@ export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
|
129
137
|
{frontMatter.title}
|
|
130
138
|
</Heading>
|
|
131
139
|
)}
|
|
132
|
-
{frontMatter.image && (
|
|
133
|
-
<Box paddingBlockEnd={16}>
|
|
134
|
-
<Hero.Image src={frontMatter.image} alt={frontMatter['image-alt']} />
|
|
135
|
-
</Box>
|
|
136
|
-
)}
|
|
137
140
|
{frontMatter.description && (
|
|
138
141
|
<Text as="p" variant="muted" size="300">
|
|
139
142
|
{frontMatter.description}
|
|
140
143
|
</Text>
|
|
141
144
|
)}
|
|
145
|
+
{frontMatter.image && (
|
|
146
|
+
<Box paddingBlockStart={16}>
|
|
147
|
+
<Hero.Image src={frontMatter.image} alt={frontMatter['image-alt']} />
|
|
148
|
+
</Box>
|
|
149
|
+
)}
|
|
142
150
|
{frontMatter['action-1-text'] && (
|
|
143
151
|
<Box paddingBlockStart={16}>
|
|
144
152
|
<ButtonGroup>
|
|
@@ -159,7 +167,11 @@ export function Theme({children, pageOpts}: NextraThemeLayoutProps) {
|
|
|
159
167
|
</>
|
|
160
168
|
)}
|
|
161
169
|
<article className={route !== '/' && !isIndexPage ? bodyStyles.Prose : ''}>
|
|
162
|
-
{isIndexPage ?
|
|
170
|
+
{isIndexPage ? (
|
|
171
|
+
<IndexCards folderData={flatDocsDirectories} route={route} />
|
|
172
|
+
) : (
|
|
173
|
+
<MDXProvider components={getComponents()}>{children}</MDXProvider>
|
|
174
|
+
)}
|
|
163
175
|
</article>
|
|
164
176
|
<footer>
|
|
165
177
|
<Box marginBlockStart={64}>
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import React, {useMemo} from 'react'
|
|
2
|
+
import NextLink from 'next/link'
|
|
2
3
|
import {NavList} from '@primer/react'
|
|
3
4
|
import {Folder, MdxFile, PageMapItem} from 'nextra'
|
|
4
5
|
import {useRouter} from 'next/router'
|
|
5
6
|
import getConfig from 'next/config'
|
|
6
7
|
|
|
7
8
|
import styles from './Sidebar.module.css'
|
|
8
|
-
import {
|
|
9
|
-
BookmarkIcon,
|
|
10
|
-
BrowserIcon,
|
|
11
|
-
Icon,
|
|
12
|
-
ImageIcon,
|
|
13
|
-
LinkExternalIcon,
|
|
14
|
-
OrganizationIcon,
|
|
15
|
-
RepoIcon,
|
|
16
|
-
StackIcon,
|
|
17
|
-
StarIcon,
|
|
18
|
-
} from '@primer/octicons-react'
|
|
9
|
+
import {LinkExternalIcon} from '@primer/octicons-react'
|
|
19
10
|
import type {ThemeConfig} from '../../../index'
|
|
20
11
|
|
|
21
12
|
type SidebarProps = {
|
|
@@ -35,32 +26,8 @@ type DocsItem = (MdxFile | FolderWithoutChildren) & {
|
|
|
35
26
|
|
|
36
27
|
const {publicRuntimeConfig} = getConfig()
|
|
37
28
|
|
|
38
|
-
function getOcticonForType(type?: string): Icon | undefined {
|
|
39
|
-
if (!type) return undefined
|
|
40
|
-
|
|
41
|
-
switch (type) {
|
|
42
|
-
case 'repo':
|
|
43
|
-
return RepoIcon
|
|
44
|
-
case 'org':
|
|
45
|
-
return OrganizationIcon
|
|
46
|
-
case 'bookmark':
|
|
47
|
-
return BookmarkIcon
|
|
48
|
-
case 'star':
|
|
49
|
-
return StarIcon
|
|
50
|
-
case 'browser':
|
|
51
|
-
return BrowserIcon
|
|
52
|
-
case 'stack':
|
|
53
|
-
return StackIcon
|
|
54
|
-
case 'img':
|
|
55
|
-
return ImageIcon
|
|
56
|
-
default:
|
|
57
|
-
return StarIcon
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
29
|
export function Sidebar({pageMap}: SidebarProps) {
|
|
62
30
|
const router = useRouter()
|
|
63
|
-
const basePath = router.basePath
|
|
64
31
|
|
|
65
32
|
const {sidebarLinks}: ThemeConfig = publicRuntimeConfig
|
|
66
33
|
|
|
@@ -94,7 +61,7 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
94
61
|
|
|
95
62
|
if (item.kind === 'MdxPage') {
|
|
96
63
|
return (
|
|
97
|
-
<NavList.Item key={item.name} href={
|
|
64
|
+
<NavList.Item as={NextLink} key={item.name} href={item.route} sx={{textTransform: 'capitalize'}}>
|
|
98
65
|
{item.frontMatter?.title ?? item.name}
|
|
99
66
|
</NavList.Item>
|
|
100
67
|
)
|
|
@@ -109,7 +76,7 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
109
76
|
const shouldShowTabs = indexPage.frontMatter?.['show-tabs'] ?? false
|
|
110
77
|
if (shouldShowTabs) {
|
|
111
78
|
return (
|
|
112
|
-
<NavList.Item key={indexPage.name} href={
|
|
79
|
+
<NavList.Item as={NextLink} key={indexPage.name} href={indexPage.route}>
|
|
113
80
|
{(indexPage as MdxFile).frontMatter?.title || item.name}
|
|
114
81
|
</NavList.Item>
|
|
115
82
|
)
|
|
@@ -129,8 +96,9 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
129
96
|
if (child.kind === 'MdxPage') {
|
|
130
97
|
return (
|
|
131
98
|
<NavList.Item
|
|
99
|
+
as={NextLink}
|
|
132
100
|
key={child.name}
|
|
133
|
-
href={
|
|
101
|
+
href={child.route}
|
|
134
102
|
aria-current={child.route === router.pathname ? 'page' : undefined}
|
|
135
103
|
>
|
|
136
104
|
{(child as MdxFile).frontMatter?.title || item.name}
|
|
@@ -144,8 +112,9 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
144
112
|
)
|
|
145
113
|
return (
|
|
146
114
|
<NavList.Item
|
|
147
|
-
|
|
148
|
-
|
|
115
|
+
as={NextLink}
|
|
116
|
+
key={(landingPageItem as MdxFile).route}
|
|
117
|
+
href={(landingPageItem as MdxFile).route}
|
|
149
118
|
sx={{textTransform: 'capitalize'}}
|
|
150
119
|
aria-current={(landingPageItem as MdxFile).route === router.pathname ? 'page' : undefined}
|
|
151
120
|
>
|
|
@@ -165,13 +134,15 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
165
134
|
{sidebarLinks && sidebarLinks.length > 0 && (
|
|
166
135
|
<NavList.Group title="" sx={{mb: 24}}>
|
|
167
136
|
{sidebarLinks.map(link => {
|
|
168
|
-
const {leadingIcon} = link
|
|
169
137
|
const isExternalUrl = link.href.startsWith('http')
|
|
170
|
-
const LeadingIcon = getOcticonForType(leadingIcon)
|
|
171
138
|
|
|
172
139
|
return (
|
|
173
|
-
<NavList.Item
|
|
174
|
-
|
|
140
|
+
<NavList.Item
|
|
141
|
+
as={NextLink}
|
|
142
|
+
key={link.title}
|
|
143
|
+
href={link.href}
|
|
144
|
+
target={isExternalUrl ? '_blank' : undefined}
|
|
145
|
+
>
|
|
175
146
|
{link.title}
|
|
176
147
|
{isExternalUrl && (
|
|
177
148
|
<NavList.TrailingVisual>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.SkipToMainContent {
|
|
2
|
+
position: absolute;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
z-index: 999;
|
|
6
|
+
padding: var(--base-size-16);
|
|
7
|
+
background-color: var(--base-color-scale-blue-5);
|
|
8
|
+
color: var(--base-color-scale-white-0);
|
|
9
|
+
}
|
|
10
|
+
.SkipToMainContent:not(:focus) {
|
|
11
|
+
clip: rect(1px, 1px, 1px, 1px);
|
|
12
|
+
clip-path: inset(50%);
|
|
13
|
+
height: 1px;
|
|
14
|
+
width: 1px;
|
|
15
|
+
margin: -1px;
|
|
16
|
+
padding: 0px;
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React, {HTMLAttributes, PropsWithChildren} from 'react'
|
|
2
|
+
import styles from './SkipToMainContent.module.css'
|
|
3
|
+
|
|
4
|
+
type SkipToMainContentProps = {
|
|
5
|
+
href: string
|
|
6
|
+
} & HTMLAttributes<HTMLAnchorElement>
|
|
7
|
+
|
|
8
|
+
export function SkipToMainContent({children, href, ...rest}: PropsWithChildren<SkipToMainContentProps>) {
|
|
9
|
+
return (
|
|
10
|
+
<a href={href} className={styles.SkipToMainContent} {...rest}>
|
|
11
|
+
{children}
|
|
12
|
+
</a>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {useEffect} from 'react'
|
|
1
|
+
import React, {useEffect, useMemo} from 'react'
|
|
2
2
|
import {NavList} from '@primer/react'
|
|
3
3
|
import {Text} from '@primer/react-brand'
|
|
4
4
|
import {Heading as HeadingType} from 'nextra'
|
|
@@ -10,6 +10,8 @@ type TableOfContentsProps = {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function TableOfContents({headings}: TableOfContentsProps) {
|
|
13
|
+
const depth2Headings = useMemo(() => headings.filter(heading => heading.depth === 2), [headings])
|
|
14
|
+
|
|
13
15
|
useEffect(() => {
|
|
14
16
|
const observer = new IntersectionObserver(
|
|
15
17
|
entries => {
|
|
@@ -40,7 +42,7 @@ export function TableOfContents({headings}: TableOfContentsProps) {
|
|
|
40
42
|
},
|
|
41
43
|
)
|
|
42
44
|
|
|
43
|
-
for (const heading of
|
|
45
|
+
for (const heading of depth2Headings) {
|
|
44
46
|
const el = document.getElementById(heading.id)
|
|
45
47
|
if (el) {
|
|
46
48
|
observer.observe(el)
|
|
@@ -50,7 +52,7 @@ export function TableOfContents({headings}: TableOfContentsProps) {
|
|
|
50
52
|
return () => {
|
|
51
53
|
observer.disconnect()
|
|
52
54
|
}
|
|
53
|
-
}, [
|
|
55
|
+
}, [depth2Headings])
|
|
54
56
|
|
|
55
57
|
return (
|
|
56
58
|
<aside className={styles.wrapper}>
|
|
@@ -58,7 +60,7 @@ export function TableOfContents({headings}: TableOfContentsProps) {
|
|
|
58
60
|
On this page
|
|
59
61
|
</Text>
|
|
60
62
|
<NavList>
|
|
61
|
-
{
|
|
63
|
+
{depth2Headings.map(heading => (
|
|
62
64
|
<NavList.Item
|
|
63
65
|
className={styles.item}
|
|
64
66
|
key={heading.id}
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
}
|
package/css/prose.module.css
CHANGED
|
@@ -129,15 +129,12 @@
|
|
|
129
129
|
letter-spacing: var(--brand-heading-letterSpacing-300);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
.Prose :is(h1, h2, h3) {
|
|
133
|
-
--spacing: var(--base-size-64);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
132
|
.Prose :is(h1) {
|
|
133
|
+
--spacing: var(--base-size-64);
|
|
137
134
|
margin-block-end: var(--spacing);
|
|
138
135
|
}
|
|
139
136
|
|
|
140
|
-
.Prose :is(
|
|
137
|
+
.Prose :is(h2, h3) + * {
|
|
141
138
|
--spacing: var(--base-size-40);
|
|
142
139
|
}
|
|
143
140
|
|
package/package.json
CHANGED