@primer/doctocat-nextjs 0.2.0 → 0.3.0-rc.c313ac3
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 +14 -0
- package/components/content/caption/Caption.tsx +1 -1
- package/components/context/color-modes/context.ts +3 -1
- package/components/index.ts +2 -0
- package/components/layout/article/AccessibilityLabel.module.css +21 -0
- package/components/layout/article/AccessibilityLabel.tsx +19 -0
- package/components/layout/article/Article.module.css +22 -1
- package/components/layout/article/Article.tsx +43 -4
- package/components/layout/article/ReadinessLabel.module.css +21 -0
- package/components/layout/article/ReadinessLabel.tsx +15 -0
- package/components/layout/article/SourceLink.module.css +7 -0
- package/components/layout/article/SourceLink.tsx +64 -0
- package/components/layout/code-block/CodeBlock.tsx +18 -0
- package/components/layout/code-block/ReactCodeBlock.module.css +68 -0
- package/components/layout/code-block/ReactCodeBlock.tsx +101 -0
- package/components/layout/code-block/syntax-highlighting-themes.ts +55 -0
- package/components/layout/header/Header.module.css +1 -0
- package/components/layout/header/Header.tsx +13 -15
- package/components/layout/index-cards/IndexCards.tsx +7 -1
- package/components/layout/prop-values/PropValues.tsx +54 -0
- package/components/layout/root-layout/Theme.tsx +135 -112
- package/components/layout/underline-nav/UnderlineNav.tsx +1 -1
- package/css/prose.module.css +88 -48
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @primer/doctocat-nextjs
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#22](https://github.com/primer/doctocat-nextjs/pull/22) [`2b57bc4`](https://github.com/primer/doctocat-nextjs/commit/2b57bc456efc03c99255ca90098ca3e035da1206) Thanks [@rezrah](https://github.com/rezrah)! - Add live code editing and previews for `jsx` code blocks in Markdown. All other code blocks will continue to render as normal.
|
|
8
|
+
|
|
9
|
+
E.g.
|
|
10
|
+
|
|
11
|
+
<pre>
|
|
12
|
+
```jsx
|
|
13
|
+
<p>Your React code here</p>
|
|
14
|
+
```
|
|
15
|
+
</pre>
|
|
16
|
+
|
|
3
17
|
## 0.2.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
|
@@ -2,5 +2,5 @@ import React, {PropsWithChildren} from 'react'
|
|
|
2
2
|
import {Text} from '@primer/react'
|
|
3
3
|
|
|
4
4
|
export function Caption(props: PropsWithChildren) {
|
|
5
|
-
return <Text as="
|
|
5
|
+
return <Text as="span" {...props} sx={{mt: 2, mb: 3, fontSize: 1, color: 'var(--brand-color-text-default)'}} />
|
|
6
6
|
}
|
package/components/index.ts
CHANGED
|
@@ -7,3 +7,5 @@ export * from './library'
|
|
|
7
7
|
export {TableOfContents} from './layout/table-of-contents/TableOfContents'
|
|
8
8
|
export {Article} from './layout/article/Article'
|
|
9
9
|
export {HeadingLink} from './layout/heading-link/HeadingLinks'
|
|
10
|
+
export {CodeBlock} from './layout/code-block/CodeBlock'
|
|
11
|
+
export {PropTableValues} from './layout/prop-values/PropValues'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.reviewedLabel {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: var(--base-size-8);
|
|
5
|
+
background-color: var(--base-color-scale-purple-0);
|
|
6
|
+
border-color: transparent;
|
|
7
|
+
color: var(--brand-color-text-default);
|
|
8
|
+
font-weight: var(--brand-text-weight-300);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
[data-color-mode='dark'] .reviewedLabel {
|
|
12
|
+
background-color: var(--base-color-scale-purple-8);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.icon {
|
|
16
|
+
fill: var(--base-color-scale-purple-5);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[data-color-mode='dark'] .icon {
|
|
20
|
+
fill: var(--base-color-scale-purple-1);
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import {Label} from '@primer/react'
|
|
3
|
+
import {AccessibilityInsetIcon} from '@primer/octicons-react'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
import styles from './AccessibilityLabel.module.css'
|
|
7
|
+
|
|
8
|
+
type AccessibilityLabelProps = {
|
|
9
|
+
short?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function AccessibilityLabel({short}: AccessibilityLabelProps) {
|
|
13
|
+
return (
|
|
14
|
+
<Label size="large" className={styles.reviewedLabel}>
|
|
15
|
+
<AccessibilityInsetIcon className={styles.icon} />
|
|
16
|
+
{short ? 'Reviewed' : 'Reviewed for accessibility'}
|
|
17
|
+
</Label>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -3,6 +3,27 @@
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
.Article--withToc {
|
|
6
|
-
grid-template-columns: 1fr 200px;
|
|
7
6
|
gap: var(--base-size-48);
|
|
8
7
|
}
|
|
8
|
+
|
|
9
|
+
.main {
|
|
10
|
+
order: 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.aside {
|
|
14
|
+
order: 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@media screen and (min-width: 768px) {
|
|
18
|
+
.main {
|
|
19
|
+
order: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.aside {
|
|
23
|
+
order: 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.Article--withToc {
|
|
27
|
+
grid-template-columns: 1fr 200px;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client'
|
|
1
2
|
import React, {PropsWithChildren} from 'react'
|
|
2
3
|
import {TableOfContents} from '../table-of-contents/TableOfContents'
|
|
3
4
|
import styles from './Article.module.css'
|
|
@@ -5,20 +6,58 @@ import bodyStyles from '../../../css/prose.module.css'
|
|
|
5
6
|
import {Heading as HeadingType} from 'nextra'
|
|
6
7
|
|
|
7
8
|
import clsx from 'clsx'
|
|
9
|
+
import {AccessibilityLabel} from './AccessibilityLabel'
|
|
10
|
+
import {Box, Stack} from '@primer/react-brand'
|
|
11
|
+
import {ReadinessLabel} from './ReadinessLabel'
|
|
12
|
+
import {SourceLink} from './SourceLink'
|
|
8
13
|
|
|
9
14
|
type Props = {
|
|
10
15
|
toc: HeadingType[]
|
|
11
16
|
metadata: {
|
|
12
17
|
layout?: string
|
|
18
|
+
[key: string]: unknown
|
|
19
|
+
figma?: string
|
|
20
|
+
source?: string
|
|
21
|
+
storybook?: string
|
|
13
22
|
}
|
|
14
23
|
}
|
|
15
24
|
|
|
16
25
|
export function Article({children, toc, metadata}: PropsWithChildren<Props>) {
|
|
17
26
|
const hasToc = toc.length > 0
|
|
27
|
+
|
|
28
|
+
const hasMetadata = Boolean(
|
|
29
|
+
metadata.ready || metadata.a11yReviewed || metadata.source || metadata.figma || metadata.storybook,
|
|
30
|
+
)
|
|
31
|
+
|
|
18
32
|
return (
|
|
19
|
-
|
|
20
|
-
<div className={clsx(
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
<>
|
|
34
|
+
<div className={clsx(styles.Article, hasToc && styles['Article--withToc'])}>
|
|
35
|
+
<div className={styles.main}>
|
|
36
|
+
{hasMetadata ? (
|
|
37
|
+
<Box marginBlockEnd={48}>
|
|
38
|
+
<Stack padding="none" direction="horizontal" justifyContent="space-between">
|
|
39
|
+
{metadata.ready || metadata.a11yReviewed ? (
|
|
40
|
+
<Stack direction="horizontal" gap={8} padding="none">
|
|
41
|
+
{metadata.ready === true && <ReadinessLabel />}
|
|
42
|
+
{typeof metadata.a11yReviewed === 'boolean' && metadata.a11yReviewed && <AccessibilityLabel />}
|
|
43
|
+
</Stack>
|
|
44
|
+
) : null}
|
|
45
|
+
<Stack direction="horizontal" gap={16} padding="none">
|
|
46
|
+
{metadata.source ? <SourceLink type="github" href={metadata.source} /> : null}
|
|
47
|
+
{metadata.figma ? <SourceLink type="figma" href={metadata.figma} /> : null}
|
|
48
|
+
{metadata.storybook ? <SourceLink type="storybook" href={metadata.storybook} /> : null}
|
|
49
|
+
</Stack>
|
|
50
|
+
</Stack>
|
|
51
|
+
</Box>
|
|
52
|
+
) : null}
|
|
53
|
+
<div className={clsx(metadata.layout !== 'custom' && bodyStyles.Prose)}>{children}</div>
|
|
54
|
+
</div>
|
|
55
|
+
{hasToc && (
|
|
56
|
+
<div className={styles.aside}>
|
|
57
|
+
<TableOfContents headings={toc} />
|
|
58
|
+
</div>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
</>
|
|
23
62
|
)
|
|
24
63
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.label {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: var(--base-size-8);
|
|
5
|
+
background-color: var(--base-color-scale-green-0);
|
|
6
|
+
border-color: transparent;
|
|
7
|
+
color: var(--brand-color-text-default);
|
|
8
|
+
font-weight: var(--brand-text-weight-300);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
[data-color-mode='dark'] .label {
|
|
12
|
+
background-color: var(--base-color-scale-green-8);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.icon {
|
|
16
|
+
fill: var(--base-color-scale-green-5);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[data-color-mode='dark'] .icon {
|
|
20
|
+
fill: var(--base-color-scale-green-1);
|
|
21
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import {Label} from '@primer/react'
|
|
4
|
+
import {CheckIcon} from '@primer/octicons-react'
|
|
5
|
+
|
|
6
|
+
import styles from './ReadinessLabel.module.css'
|
|
7
|
+
|
|
8
|
+
export function ReadinessLabel() {
|
|
9
|
+
return (
|
|
10
|
+
<Label size="large" className={styles.label}>
|
|
11
|
+
<CheckIcon className={styles.icon} />
|
|
12
|
+
Ready to use
|
|
13
|
+
</Label>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {InlineLink, Stack, Text} from '@primer/react-brand'
|
|
2
|
+
import {BookIcon, MarkGithubIcon} from '@primer/octicons-react'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
import styles from './SourceLink.module.css'
|
|
6
|
+
|
|
7
|
+
type SourceLinkProps = {
|
|
8
|
+
type: 'github' | 'storybook' | 'figma'
|
|
9
|
+
href: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function SourceLink({href, type}: SourceLinkProps) {
|
|
13
|
+
return (
|
|
14
|
+
<div className="custom-component">
|
|
15
|
+
<Stack padding="none" direction="horizontal" alignItems="center" gap={4}>
|
|
16
|
+
{type === 'github' ? <MarkGithubIcon className={styles.icon} /> : null}
|
|
17
|
+
{type === 'storybook' ? <BookIcon className={styles.icon} /> : null}
|
|
18
|
+
{type === 'figma' ? <FigmaLogo className={styles.icon} /> : null}
|
|
19
|
+
|
|
20
|
+
{type === 'github' ? (
|
|
21
|
+
<Text size="100">
|
|
22
|
+
<InlineLink href={href} className={styles.link} target="_blank">
|
|
23
|
+
GitHub
|
|
24
|
+
</InlineLink>
|
|
25
|
+
</Text>
|
|
26
|
+
) : null}
|
|
27
|
+
{type === 'storybook' ? (
|
|
28
|
+
<Text size="100">
|
|
29
|
+
<InlineLink href={href} className={styles.link} target="_blank">
|
|
30
|
+
Storybook
|
|
31
|
+
</InlineLink>
|
|
32
|
+
</Text>
|
|
33
|
+
) : null}
|
|
34
|
+
{type === 'figma' ? (
|
|
35
|
+
<Text size="100">
|
|
36
|
+
<InlineLink href={href} className={styles.link} target="_blank">
|
|
37
|
+
Figma
|
|
38
|
+
</InlineLink>
|
|
39
|
+
</Text>
|
|
40
|
+
) : null}
|
|
41
|
+
</Stack>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function FigmaLogo({className}: {className?: string}) {
|
|
47
|
+
return (
|
|
48
|
+
<svg
|
|
49
|
+
className={className}
|
|
50
|
+
viewBox="0 0 16 16"
|
|
51
|
+
aria-hidden="true"
|
|
52
|
+
width={16}
|
|
53
|
+
height={16}
|
|
54
|
+
fill="currentColor"
|
|
55
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
56
|
+
>
|
|
57
|
+
<path
|
|
58
|
+
fillRule="evenodd"
|
|
59
|
+
clipRule="evenodd"
|
|
60
|
+
d="M5.417 0A3.167 3.167 0 0 0 3.37 5.583 3.16 3.16 0 0 0 2.25 8a3.16 3.16 0 0 0 1.12 2.417 3.167 3.167 0 1 0 5.213 2.417V10.687a3.165 3.165 0 0 0 3.87-4.964A3.167 3.167 0 0 0 10.582 0H5.417Zm4.727 6.333h.21a1.665 1.665 0 1 1-.21 0Zm.25-1.5h.19a1.667 1.667 0 1 0 0-3.333H5.416a1.667 1.667 0 1 0 0 3.333h4.687a3.226 3.226 0 0 1 .29 0ZM3.75 8c0-.92.746-1.667 1.667-1.667h1.666v3.334H5.417C4.497 9.667 3.75 8.92 3.75 8Zm1.667 3.167a1.667 1.667 0 1 0 1.666 1.667v-1.667H5.417Z"
|
|
61
|
+
/>
|
|
62
|
+
</svg>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React, {PropsWithChildren} from 'react'
|
|
3
|
+
|
|
4
|
+
import {ReactCodeBlock} from './ReactCodeBlock'
|
|
5
|
+
import {Pre} from 'nextra/components'
|
|
6
|
+
|
|
7
|
+
type CodeBlockProps = {
|
|
8
|
+
'data-language': string
|
|
9
|
+
jsxScope: Record<string, unknown>
|
|
10
|
+
} & PropsWithChildren<HTMLElement>
|
|
11
|
+
|
|
12
|
+
export function CodeBlock(props: CodeBlockProps) {
|
|
13
|
+
if (['tsx', 'jsx'].includes(props['data-language'])) {
|
|
14
|
+
return <ReactCodeBlock {...props} />
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return <Pre>{props.children}</Pre>
|
|
18
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
.CodeBlock {
|
|
2
|
+
margin-block: var(--base-size-24);
|
|
3
|
+
background-color: var(--brand-color-canvas-default);
|
|
4
|
+
border: var(--brand-borderWidth-thin) solid var(--brand-color-border-default);
|
|
5
|
+
border-radius: var(--brand-borderRadius-large);
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
width: 100%;
|
|
10
|
+
position: relative;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.Preview {
|
|
14
|
+
display: flex;
|
|
15
|
+
width: 100%;
|
|
16
|
+
padding: var(--base-size-16);
|
|
17
|
+
padding-block: var(--base-size-64);
|
|
18
|
+
min-height: 240px;
|
|
19
|
+
flex: 1 1;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.Editor {
|
|
25
|
+
font-size: var(--brand-text-size-100);
|
|
26
|
+
line-height: var(--brand-text-lineHeight-100);
|
|
27
|
+
font-family: var(--brand-fontStack-monospace);
|
|
28
|
+
background-color: var(--brand-color-canvas-subtle);
|
|
29
|
+
overflow: auto;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.Editor pre {
|
|
33
|
+
font-size: inherit;
|
|
34
|
+
border-radius: 0;
|
|
35
|
+
padding: var(--base-size-16) !important;
|
|
36
|
+
background-color: var(--brand-color-canvas-subtle) !important;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.Toolbar {
|
|
40
|
+
display: flex;
|
|
41
|
+
gap: var(--base-size-8);
|
|
42
|
+
padding-inline: var(--base-size-16);
|
|
43
|
+
padding-block-start: var(--base-size-16);
|
|
44
|
+
border-top: var(--brand-borderWidth-thin) solid var(--brand-color-border-default);
|
|
45
|
+
background-color: var(--brand-color-canvas-subtle);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.Error pre {
|
|
49
|
+
margin-block: 0 !important;
|
|
50
|
+
border-radius: 0;
|
|
51
|
+
font-size: var(--brand-text-size-100);
|
|
52
|
+
line-height: var(--brand-text-lineHeight-100);
|
|
53
|
+
font-family: var(--brand-fontStack-monospace);
|
|
54
|
+
color: var(--brand-color-error-fg);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.colorModeMenu {
|
|
58
|
+
display: inline-block;
|
|
59
|
+
position: absolute;
|
|
60
|
+
top: var(--base-size-16);
|
|
61
|
+
right: var(--base-size-2);
|
|
62
|
+
z-index: 19;
|
|
63
|
+
width: 200px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.colorModeButtonActive {
|
|
67
|
+
background-color: var(--brand-color-canvas-subtle);
|
|
68
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React, {PropsWithChildren, useCallback, useState} from 'react'
|
|
3
|
+
import clsx from 'clsx'
|
|
4
|
+
import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live'
|
|
5
|
+
import {useColorMode} from '../../context/color-modes/useColorMode'
|
|
6
|
+
import styles from './ReactCodeBlock.module.css'
|
|
7
|
+
import {ActionBar, Button, ThemeProvider} from '@primer/react'
|
|
8
|
+
import {CopyIcon, MoonIcon, SunIcon, UndoIcon} from '@primer/octicons-react'
|
|
9
|
+
import {colorModes} from '../../context/color-modes/context'
|
|
10
|
+
|
|
11
|
+
import {lightTheme, darkTheme} from './syntax-highlighting-themes'
|
|
12
|
+
|
|
13
|
+
type ReactCodeBlockProps = {
|
|
14
|
+
'data-language': string
|
|
15
|
+
'data-filename'?: string
|
|
16
|
+
jsxScope: Record<string, unknown>
|
|
17
|
+
} & PropsWithChildren<HTMLElement>
|
|
18
|
+
|
|
19
|
+
export function ReactCodeBlock(props: ReactCodeBlockProps) {
|
|
20
|
+
const {colorMode, setColorMode} = useColorMode()
|
|
21
|
+
const initialCode = getCodeFromChildren(props.children)
|
|
22
|
+
const [code, setCode] = useState(initialCode)
|
|
23
|
+
const shouldShowPreview = ['tsx', 'jsx'].includes(props['data-language'])
|
|
24
|
+
|
|
25
|
+
const handleReset = useCallback(() => {
|
|
26
|
+
setCode(initialCode)
|
|
27
|
+
}, [initialCode, setCode])
|
|
28
|
+
|
|
29
|
+
const handleCopy = useCallback(() => {
|
|
30
|
+
navigator.clipboard.writeText(code)
|
|
31
|
+
}, [code])
|
|
32
|
+
|
|
33
|
+
const noInline = props['data-filename'] === 'noinline' || false
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
<LiveProvider code={code} scope={props.jsxScope} noInline={noInline}>
|
|
38
|
+
<div className={clsx(styles.CodeBlock, 'custom-component')}>
|
|
39
|
+
{shouldShowPreview && (
|
|
40
|
+
<div>
|
|
41
|
+
<div className={styles.colorModeMenu}>
|
|
42
|
+
<ActionBar aria-label="Toolbar">
|
|
43
|
+
{colorModes.map((mode, index) => {
|
|
44
|
+
const Icon = mode === 'light' ? SunIcon : MoonIcon
|
|
45
|
+
return (
|
|
46
|
+
<ActionBar.IconButton
|
|
47
|
+
className={clsx(styles.colorModeButton, colorMode === mode && styles.colorModeButtonActive)}
|
|
48
|
+
key={`color-mode-${mode}-${index}`}
|
|
49
|
+
icon={Icon}
|
|
50
|
+
aria-label={mode}
|
|
51
|
+
onClick={() => setColorMode(mode)}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
})}
|
|
55
|
+
</ActionBar>
|
|
56
|
+
</div>
|
|
57
|
+
<ThemeProvider colorMode={colorMode}>
|
|
58
|
+
<div className="custom-component">
|
|
59
|
+
<LivePreview className={styles.Preview} />
|
|
60
|
+
</div>
|
|
61
|
+
</ThemeProvider>
|
|
62
|
+
</div>
|
|
63
|
+
)}
|
|
64
|
+
<div className={styles.Toolbar}>
|
|
65
|
+
<Button size="small" leadingVisual={CopyIcon} onClick={handleCopy}>
|
|
66
|
+
Copy
|
|
67
|
+
</Button>
|
|
68
|
+
<Button size="small" leadingVisual={UndoIcon} onClick={handleReset}>
|
|
69
|
+
Reset
|
|
70
|
+
</Button>
|
|
71
|
+
</div>
|
|
72
|
+
<div className={styles.Editor}>
|
|
73
|
+
<LiveEditor theme={colorMode === 'light' ? lightTheme : darkTheme} onChange={setCode} />
|
|
74
|
+
</div>
|
|
75
|
+
{shouldShowPreview && (
|
|
76
|
+
<div className={styles.Error}>
|
|
77
|
+
<LiveError />
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
</LiveProvider>
|
|
82
|
+
</>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Helper function to turn Nextra <code> children into plain text
|
|
88
|
+
*/
|
|
89
|
+
function getCodeFromChildren(children: React.ReactNode) {
|
|
90
|
+
if (!React.isValidElement(children) || !children.props?.children) return ''
|
|
91
|
+
|
|
92
|
+
// Flattens the nested spans and combine their text content if it's a react child
|
|
93
|
+
const extractText = (node: React.ReactNode): string => {
|
|
94
|
+
if (typeof node === 'string') return node
|
|
95
|
+
if (Array.isArray(node)) return node.map(extractText).join('')
|
|
96
|
+
if (React.isValidElement(node) && node.props?.children) return extractText(node.props.children)
|
|
97
|
+
return ''
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return extractText(children)
|
|
101
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const lightTheme = {
|
|
2
|
+
plain: {
|
|
3
|
+
backgroundColor: '#ffffff',
|
|
4
|
+
color: '#24292e',
|
|
5
|
+
},
|
|
6
|
+
styles: [
|
|
7
|
+
{
|
|
8
|
+
types: ['comment'],
|
|
9
|
+
style: {
|
|
10
|
+
color: '#6a737d',
|
|
11
|
+
fontStyle: 'italic' as const,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
types: ['string', 'number', 'builtin', 'variable'],
|
|
16
|
+
style: {
|
|
17
|
+
color: '#032f62',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
types: ['class-name', 'function', 'tag', 'attr-name'],
|
|
22
|
+
style: {
|
|
23
|
+
color: '#005CC5',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const darkTheme = {
|
|
30
|
+
plain: {
|
|
31
|
+
backgroundColor: '#0d1117',
|
|
32
|
+
color: '#c9d1d9',
|
|
33
|
+
},
|
|
34
|
+
styles: [
|
|
35
|
+
{
|
|
36
|
+
types: ['comment'],
|
|
37
|
+
style: {
|
|
38
|
+
color: '#8b949e',
|
|
39
|
+
fontStyle: 'italic' as const,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
types: ['string', 'number', 'builtin', 'variable'],
|
|
44
|
+
style: {
|
|
45
|
+
color: '#a5d6ff',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
types: ['class-name', 'function', 'tag', 'attr-name'],
|
|
50
|
+
style: {
|
|
51
|
+
color: '#d2a8ff',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
padding: var(--base-size-20) var(--base-size-12) var(--base-size-20) var(--base-size-16);
|
|
7
7
|
border-bottom: var(--brand-borderWidth-thin) solid var(--brand-color-border-default);
|
|
8
8
|
background: var(--brand-color-canvas-default);
|
|
9
|
+
z-index: 20;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
@media (max-width: 768px) {
|
|
@@ -3,7 +3,7 @@ import {MarkGithubIcon, MoonIcon, SearchIcon, SunIcon, ThreeBarsIcon, XIcon} fro
|
|
|
3
3
|
import {Box, FormControl, IconButton, TextInput} from '@primer/react'
|
|
4
4
|
import {Heading, Stack, Text} from '@primer/react-brand'
|
|
5
5
|
import {clsx} from 'clsx'
|
|
6
|
-
import {MdxFile,
|
|
6
|
+
import {MdxFile, PageMapItem} from 'nextra'
|
|
7
7
|
import {debounce} from 'lodash'
|
|
8
8
|
|
|
9
9
|
import Link from 'next/link'
|
|
@@ -11,11 +11,11 @@ import styles from './Header.module.css'
|
|
|
11
11
|
import {NavDrawer} from '../nav-drawer/NavDrawer'
|
|
12
12
|
import {useNavDrawerState} from '../nav-drawer/useNavDrawerState'
|
|
13
13
|
import {useColorMode} from '../../context/color-modes/useColorMode'
|
|
14
|
-
import {hasChildren} from '../../../helpers/hasChildren'
|
|
15
14
|
import {DocsItem} from '../../../types'
|
|
16
15
|
|
|
17
16
|
type HeaderProps = {
|
|
18
17
|
pageMap: PageMapItem[]
|
|
18
|
+
flatDocsDirectories: DocsItem[]
|
|
19
19
|
siteTitle: string
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -25,7 +25,7 @@ type SearchResults = {
|
|
|
25
25
|
url: string
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function Header({pageMap, siteTitle}: HeaderProps) {
|
|
28
|
+
export function Header({pageMap, siteTitle, flatDocsDirectories}: HeaderProps) {
|
|
29
29
|
const {colorMode, setColorMode} = useColorMode()
|
|
30
30
|
const inputRef = useRef<HTMLInputElement | null>(null)
|
|
31
31
|
const searchResultsRef = useRef<HTMLElement | null>(null)
|
|
@@ -74,32 +74,30 @@ export function Header({pageMap, siteTitle}: HeaderProps) {
|
|
|
74
74
|
}, [colorMode])
|
|
75
75
|
|
|
76
76
|
const setSearchResultsDebounced = debounce((data: SearchResults[] | undefined) => setSearchResults(data), 1000)
|
|
77
|
-
|
|
78
77
|
const searchData = useMemo(
|
|
79
78
|
() =>
|
|
80
|
-
|
|
79
|
+
flatDocsDirectories
|
|
81
80
|
.map(item => {
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
if ((item as DocsItem).type === 'doc') {
|
|
86
|
-
return item
|
|
87
|
-
}
|
|
81
|
+
if (item.route === '/') return null // remove homepage
|
|
82
|
+
return item
|
|
88
83
|
})
|
|
89
|
-
.flat()
|
|
90
84
|
.filter(Boolean)
|
|
91
85
|
.map(item => {
|
|
92
86
|
const {frontMatter, route} = item as MdxFile
|
|
93
|
-
|
|
94
87
|
if (!frontMatter) return null
|
|
95
88
|
const result = {
|
|
96
|
-
title:
|
|
89
|
+
title:
|
|
90
|
+
frontMatter['show-tabs'] && frontMatter['tab-label']
|
|
91
|
+
? `${frontMatter.title} | ${frontMatter['tab-label']}`
|
|
92
|
+
: frontMatter.title
|
|
93
|
+
? frontMatter.title
|
|
94
|
+
: '',
|
|
97
95
|
description: frontMatter.description ? frontMatter.description : '',
|
|
98
96
|
url: route,
|
|
99
97
|
}
|
|
100
98
|
return result
|
|
101
99
|
}),
|
|
102
|
-
[
|
|
100
|
+
[flatDocsDirectories],
|
|
103
101
|
)
|
|
104
102
|
|
|
105
103
|
const handleChange = () => {
|
|
@@ -11,7 +11,13 @@ type IndexCardsProps = {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export function IndexCards({route, folderData}: IndexCardsProps) {
|
|
14
|
-
|
|
14
|
+
// We don't want to show children of these pages. E.g. tabbed pages
|
|
15
|
+
const onlyDirectChildren = folderData.filter(
|
|
16
|
+
item => item.route.includes(`${route}/`) && item.route.split('/').length === 3,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
const filteredData = onlyDirectChildren.filter(item => item.type === 'doc' && item.route.includes(`${route}/`))
|
|
20
|
+
|
|
15
21
|
return (
|
|
16
22
|
<Stack direction="vertical" padding="none" gap="spacious">
|
|
17
23
|
{filteredData.map((item: DocsItem) => {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
type PropTableValuesProps = {
|
|
5
|
+
values: (string | number)[]
|
|
6
|
+
addLineBreaks?: boolean
|
|
7
|
+
commaSeparated?: boolean
|
|
8
|
+
removeApostrophes?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function PropTableValues({values, addLineBreaks, commaSeparated, removeApostrophes}: PropTableValuesProps) {
|
|
12
|
+
const valuesToRender = values.map(value => {
|
|
13
|
+
if (typeof value === 'string' && !removeApostrophes) {
|
|
14
|
+
return (
|
|
15
|
+
<span key={value}>
|
|
16
|
+
<code>'{value}'</code>
|
|
17
|
+
</span>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
return (
|
|
21
|
+
<span key={value}>
|
|
22
|
+
<code> {value}</code>
|
|
23
|
+
</span>
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
if (commaSeparated) {
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
{valuesToRender.reduce((acc, curr, index) => (
|
|
31
|
+
<React.Fragment key={index}>
|
|
32
|
+
{acc}
|
|
33
|
+
{index > 0 && ', '}
|
|
34
|
+
{curr}
|
|
35
|
+
</React.Fragment>
|
|
36
|
+
))}
|
|
37
|
+
{addLineBreaks && <br />}
|
|
38
|
+
</>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<>
|
|
44
|
+
{valuesToRender.map(value => {
|
|
45
|
+
return (
|
|
46
|
+
<React.Fragment key={value.key}>
|
|
47
|
+
{value}
|
|
48
|
+
{addLineBreaks && <br />}
|
|
49
|
+
</React.Fragment>
|
|
50
|
+
)
|
|
51
|
+
})}
|
|
52
|
+
</>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -5,7 +5,8 @@ import Head from 'next/head'
|
|
|
5
5
|
import type {Folder, MdxFile, PageMapItem} from 'nextra'
|
|
6
6
|
import {useFSRoute} from 'nextra/hooks'
|
|
7
7
|
import {BaseStyles, Box as PRCBox, Breadcrumbs, PageLayout, ThemeProvider} from '@primer/react'
|
|
8
|
-
|
|
8
|
+
import '@primer/primitives/dist/css/functional/themes/light.css'
|
|
9
|
+
import '@primer/primitives/dist/css/functional/themes/dark.css'
|
|
9
10
|
import {
|
|
10
11
|
Animate,
|
|
11
12
|
AnimationProvider,
|
|
@@ -83,6 +84,7 @@ export function Theme({children, pageMap}: ThemeProps) {
|
|
|
83
84
|
const filteredTabData: MdxFile[] = data && hasChildren(data) ? ((data as Folder).children as MdxFile[]) : []
|
|
84
85
|
|
|
85
86
|
const relatedLinks = getRelatedPages(route, activeMetadata, flatDocsDirectories)
|
|
87
|
+
const disablePageAnimation = activeMetadata?.options?.disablePageAnimation || false
|
|
86
88
|
return (
|
|
87
89
|
<>
|
|
88
90
|
<BrandThemeProvider dir="ltr" colorMode={colorMode}>
|
|
@@ -104,132 +106,153 @@ export function Theme({children, pageMap}: ThemeProps) {
|
|
|
104
106
|
</Head>
|
|
105
107
|
)}
|
|
106
108
|
|
|
107
|
-
<
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
<PageLayout
|
|
120
|
-
<
|
|
121
|
-
<
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
109
|
+
<ContentWrapper disableAnimations={disablePageAnimation}>
|
|
110
|
+
<PRCBox
|
|
111
|
+
sx={{
|
|
112
|
+
position: 'sticky',
|
|
113
|
+
top: 0,
|
|
114
|
+
zIndex: 99,
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
<SkipToMainContent href="#main">Skip to main content</SkipToMainContent>
|
|
118
|
+
<Header pageMap={pageMap} flatDocsDirectories={flatDocsDirectories} siteTitle={siteTitle} />
|
|
119
|
+
</PRCBox>
|
|
120
|
+
<PageLayout rowGap="none" columnGap="none" padding="none" containerWidth="full">
|
|
121
|
+
<PageLayout.Content padding="normal">
|
|
122
|
+
<div id="main">
|
|
123
|
+
<PRCBox sx={!isHomePage && {maxWidth: 1200, width: '100%', margin: '0 auto'}}>
|
|
124
|
+
<Stack direction="vertical" padding="none" gap="spacious">
|
|
125
|
+
{!isHomePage && (
|
|
126
|
+
<>
|
|
127
|
+
{activePath.length && (
|
|
128
|
+
<Breadcrumbs>
|
|
129
|
+
{siteTitle && (
|
|
130
|
+
<Breadcrumbs.Item
|
|
131
|
+
as={NextLink}
|
|
132
|
+
href="/"
|
|
133
|
+
sx={{
|
|
134
|
+
color: 'var(--brand-InlineLink-color-rest)',
|
|
135
|
+
}}
|
|
136
|
+
>
|
|
137
|
+
{siteTitle}
|
|
138
|
+
</Breadcrumbs.Item>
|
|
139
|
+
)}
|
|
140
|
+
{activePath.map((item, index) => {
|
|
141
|
+
return (
|
|
129
142
|
<Breadcrumbs.Item
|
|
130
143
|
as={NextLink}
|
|
131
|
-
|
|
144
|
+
key={item.name}
|
|
145
|
+
href={item.route}
|
|
146
|
+
selected={index === activePath.length - 1}
|
|
132
147
|
sx={{
|
|
148
|
+
textTransform: 'capitalize',
|
|
133
149
|
color: 'var(--brand-InlineLink-color-rest)',
|
|
134
150
|
}}
|
|
135
151
|
>
|
|
136
|
-
{
|
|
152
|
+
{item.title.replace(/-/g, ' ')}
|
|
137
153
|
</Breadcrumbs.Item>
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
as={NextLink}
|
|
143
|
-
key={item.name}
|
|
144
|
-
href={item.route}
|
|
145
|
-
selected={index === activePath.length - 1}
|
|
146
|
-
sx={{
|
|
147
|
-
textTransform: 'capitalize',
|
|
148
|
-
color: 'var(--brand-InlineLink-color-rest)',
|
|
149
|
-
}}
|
|
150
|
-
>
|
|
151
|
-
{item.title.replace(/-/g, ' ')}
|
|
152
|
-
</Breadcrumbs.Item>
|
|
153
|
-
)
|
|
154
|
-
})}
|
|
155
|
-
</Breadcrumbs>
|
|
156
|
-
)}
|
|
154
|
+
)
|
|
155
|
+
})}
|
|
156
|
+
</Breadcrumbs>
|
|
157
|
+
)}
|
|
157
158
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
159
|
+
<Box>
|
|
160
|
+
<Stack direction="vertical" padding="none" gap={12} alignItems="flex-start">
|
|
161
|
+
{activeMetadata?.title && (
|
|
162
|
+
<Heading as="h1" size="3">
|
|
163
|
+
{activeMetadata.title}
|
|
164
|
+
</Heading>
|
|
165
|
+
)}
|
|
166
|
+
{activeMetadata?.description && (
|
|
167
|
+
<Text as="p" variant="muted" size="300">
|
|
168
|
+
{activeMetadata.description}
|
|
169
|
+
</Text>
|
|
170
|
+
)}
|
|
171
|
+
{activeMetadata?.image && (
|
|
172
|
+
<Box paddingBlockStart={16} style={{width: '100%'}}>
|
|
173
|
+
<Hero.Image src={activeMetadata.image} alt={activeMetadata['image-alt']} />
|
|
174
|
+
</Box>
|
|
175
|
+
)}
|
|
176
|
+
{activeMetadata && activeMetadata['action-1-text'] && (
|
|
177
|
+
<Box paddingBlockStart={16}>
|
|
178
|
+
<ButtonGroup>
|
|
179
|
+
<Button as="a" href={activeMetadata['action-1-link']}>
|
|
180
|
+
{activeMetadata['action-1-text']}
|
|
181
|
+
</Button>
|
|
182
|
+
{activeMetadata['action-2-text'] && (
|
|
183
|
+
<Button as="a" variant="secondary" href={activeMetadata['action-2-link']}>
|
|
184
|
+
{activeMetadata['action-2-text']}
|
|
180
185
|
</Button>
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
186
|
+
)}
|
|
187
|
+
</ButtonGroup>
|
|
188
|
+
</Box>
|
|
189
|
+
)}
|
|
190
|
+
</Stack>
|
|
191
|
+
</Box>
|
|
192
|
+
{activeMetadata && activeMetadata['show-tabs'] && (
|
|
193
|
+
<UnderlineNav tabData={filteredTabData} />
|
|
194
|
+
)}
|
|
195
|
+
</>
|
|
196
|
+
)}
|
|
197
|
+
<article>
|
|
198
|
+
{isIndexPage ? (
|
|
199
|
+
<IndexCards folderData={flatDocsDirectories} route={route} />
|
|
200
|
+
) : (
|
|
201
|
+
<>
|
|
202
|
+
<>{children}</>
|
|
203
|
+
|
|
204
|
+
{relatedLinks.length > 0 && (
|
|
205
|
+
<PRCBox sx={{pt: 5}}>
|
|
206
|
+
<RelatedContentLinks links={relatedLinks} />
|
|
207
|
+
</PRCBox>
|
|
193
208
|
)}
|
|
194
209
|
</>
|
|
195
210
|
)}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
</PageLayout.Content>
|
|
216
|
-
<PageLayout.Pane
|
|
217
|
-
aria-label="Side navigation"
|
|
218
|
-
width="small"
|
|
219
|
-
sticky
|
|
220
|
-
padding="none"
|
|
221
|
-
position="start"
|
|
222
|
-
hidden={{narrow: true}}
|
|
223
|
-
divider="line"
|
|
224
|
-
>
|
|
225
|
-
<Sidebar pageMap={pageMap} />
|
|
226
|
-
</PageLayout.Pane>
|
|
227
|
-
</PageLayout>
|
|
228
|
-
</Animate>
|
|
229
|
-
</AnimationProvider>
|
|
211
|
+
</article>
|
|
212
|
+
<Footer filePath={filePath} repoURL={repoURL} repoSrcPath={repoSrcPath} />
|
|
213
|
+
</Stack>
|
|
214
|
+
</PRCBox>
|
|
215
|
+
</div>
|
|
216
|
+
</PageLayout.Content>
|
|
217
|
+
<PageLayout.Pane
|
|
218
|
+
aria-label="Side navigation"
|
|
219
|
+
width="small"
|
|
220
|
+
sticky
|
|
221
|
+
padding="none"
|
|
222
|
+
position="start"
|
|
223
|
+
hidden={{narrow: true}}
|
|
224
|
+
divider="line"
|
|
225
|
+
>
|
|
226
|
+
<Sidebar pageMap={pageMap} />
|
|
227
|
+
</PageLayout.Pane>
|
|
228
|
+
</PageLayout>
|
|
229
|
+
</ContentWrapper>
|
|
230
230
|
</BaseStyles>
|
|
231
231
|
</ThemeProvider>
|
|
232
232
|
</BrandThemeProvider>
|
|
233
233
|
</>
|
|
234
234
|
)
|
|
235
235
|
}
|
|
236
|
+
|
|
237
|
+
type ContentWrapperProps = PropsWithChildren<{
|
|
238
|
+
disableAnimations?: boolean
|
|
239
|
+
}>
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* The fade in animation masks the layout repainting issues.
|
|
243
|
+
* That animation however, interferes with nested AnimationProviders so we need
|
|
244
|
+
* to disable it for certain pages that use that.
|
|
245
|
+
*/
|
|
246
|
+
function ContentWrapper({children, disableAnimations}: ContentWrapperProps) {
|
|
247
|
+
if (disableAnimations) {
|
|
248
|
+
return <>{children}</>
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<>
|
|
253
|
+
<AnimationProvider runOnce visibilityOptions={1} autoStaggerChildren={false}>
|
|
254
|
+
<Animate animate="fade-in">{children}</Animate>
|
|
255
|
+
</AnimationProvider>
|
|
256
|
+
</>
|
|
257
|
+
)
|
|
258
|
+
}
|
|
@@ -41,7 +41,7 @@ export function UnderlineNav({tabData}: UnderlineNavProps) {
|
|
|
41
41
|
href={`${item.route}`}
|
|
42
42
|
aria-current={currentRoute === item.route ? 'page' : undefined}
|
|
43
43
|
>
|
|
44
|
-
{(item.frontMatter && item.frontMatter.title) || item.name}
|
|
44
|
+
{(item.frontMatter && (item.frontMatter['tab-label'] || item.frontMatter.title)) || item.name}
|
|
45
45
|
</PrimerUnderlineNav.Item>
|
|
46
46
|
)
|
|
47
47
|
})}
|
package/css/prose.module.css
CHANGED
|
@@ -32,25 +32,11 @@
|
|
|
32
32
|
/* 2. Element spacing */
|
|
33
33
|
/* ---------------------------------------------------------- */
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.Prose h2:not(:global(.custom-component) h2),
|
|
41
|
-
.Prose h3:not(:global(.custom-component) h3),
|
|
42
|
-
.Prose h4:not(:global(.custom-component) h4),
|
|
43
|
-
.Prose h5:not(:global(.custom-component) h5),
|
|
44
|
-
.Prose h6:not(:global(.custom-component) h6),
|
|
45
|
-
.Prose p:not(:global(.custom-component) p),
|
|
46
|
-
.Prose ul:not(:global(.custom-component) ul),
|
|
47
|
-
.Prose ol:not(:global(.custom-component) ol),
|
|
48
|
-
.Prose blockquote:not(:global(.custom-component) blockquote),
|
|
49
|
-
.Prose hr:not(:global(.custom-component) hr),
|
|
50
|
-
.Prose table:not(:global(.custom-component) table),
|
|
51
|
-
.Prose pre:not(:global(.custom-component) pre),
|
|
52
|
-
.Prose dl:not(:global(.custom-component) dl),
|
|
53
|
-
.Prose figure:not(:global(.custom-component) figure) {
|
|
35
|
+
.Prose
|
|
36
|
+
:is(h1, h2, h3, h4, h5, h6, p, ul, ol, blockquote, figure, hr, table, pre, dl):not(
|
|
37
|
+
:first-child,
|
|
38
|
+
:global(.custom-component) :is(h1, h2, h3, h4, h5, h6, p, ul, ol, blockquote, figure, hr, table, pre, dl)
|
|
39
|
+
) {
|
|
54
40
|
margin-block-start: var(--spacing, 1em);
|
|
55
41
|
}
|
|
56
42
|
|
|
@@ -66,7 +52,7 @@
|
|
|
66
52
|
/* 4. Headings */
|
|
67
53
|
/* ---------------------------------------------------------- */
|
|
68
54
|
|
|
69
|
-
.Prose h1 {
|
|
55
|
+
.Prose h1:not(:global(.custom-component) h1) {
|
|
70
56
|
font-weight: var(--brand-heading-weight-900);
|
|
71
57
|
font-size: var(--base-size-32);
|
|
72
58
|
line-height: 1.5;
|
|
@@ -74,11 +60,11 @@
|
|
|
74
60
|
letter-spacing: var(--brand-text-letterSpacing-800);
|
|
75
61
|
}
|
|
76
62
|
|
|
77
|
-
.Prose--lineLength h1 {
|
|
63
|
+
.Prose--lineLength h1:not(:global(.custom-component) h1) {
|
|
78
64
|
max-width: 22ch;
|
|
79
65
|
}
|
|
80
66
|
|
|
81
|
-
.Prose h2 {
|
|
67
|
+
.Prose h2:not(:global(.custom-component) h2) {
|
|
82
68
|
font-weight: var(--brand-heading-weight-700);
|
|
83
69
|
font-size: var(--base-size-24);
|
|
84
70
|
line-height: var(--base-size-24);
|
|
@@ -86,11 +72,11 @@
|
|
|
86
72
|
letter-spacing: var(--brand-text-letterSpacing-700);
|
|
87
73
|
}
|
|
88
74
|
|
|
89
|
-
.Prose--lineLength h2 {
|
|
75
|
+
.Prose--lineLength h2:not(:global(.custom-component) h2) {
|
|
90
76
|
max-width: 26ch;
|
|
91
77
|
}
|
|
92
78
|
|
|
93
|
-
.Prose h3 {
|
|
79
|
+
.Prose h3:not(:global(.custom-component) h3) {
|
|
94
80
|
font-weight: var(--brand-heading-weight-600);
|
|
95
81
|
font-size: var(--base-size-20);
|
|
96
82
|
line-height: var(--base-size-20);
|
|
@@ -98,11 +84,11 @@
|
|
|
98
84
|
letter-spacing: var(--brand-heading-letterSpacing-600);
|
|
99
85
|
}
|
|
100
86
|
|
|
101
|
-
.Prose--lineLength
|
|
87
|
+
.Prose--lineLength h3:not(:global(.custom-component) h3) {
|
|
102
88
|
max-width: 32ch;
|
|
103
89
|
}
|
|
104
90
|
|
|
105
|
-
.Prose h4 {
|
|
91
|
+
.Prose h4:not(:global(.custom-component) h4) {
|
|
106
92
|
--spacing: var(--base-size-40);
|
|
107
93
|
font-weight: var(--brand-text-weight-500);
|
|
108
94
|
font-size: var(--base-size-18);
|
|
@@ -111,7 +97,7 @@
|
|
|
111
97
|
letter-spacing: var(--brand-heading-letterSpacing-500);
|
|
112
98
|
}
|
|
113
99
|
|
|
114
|
-
.Prose h5 {
|
|
100
|
+
.Prose h5:not(:global(.custom-component) h5) {
|
|
115
101
|
--spacing: var(--base-size-40);
|
|
116
102
|
font-weight: var(--brand-text-weight-400);
|
|
117
103
|
font-size: var(--base-size-16);
|
|
@@ -120,7 +106,7 @@
|
|
|
120
106
|
letter-spacing: var(--brand-heading-letterSpacing-400);
|
|
121
107
|
}
|
|
122
108
|
|
|
123
|
-
.Prose h6 {
|
|
109
|
+
.Prose h6:not(:global(.custom-component) h6) {
|
|
124
110
|
--spacing: var(--base-size-48);
|
|
125
111
|
font-weight: var(--brand-text-subhead-weight-large);
|
|
126
112
|
font-size: var(--base-size-14);
|
|
@@ -129,12 +115,12 @@
|
|
|
129
115
|
letter-spacing: var(--brand-heading-letterSpacing-300);
|
|
130
116
|
}
|
|
131
117
|
|
|
132
|
-
.Prose :is(h1) {
|
|
118
|
+
.Prose :is(h1):not(:global(.custom-component) h1) {
|
|
133
119
|
--spacing: var(--base-size-64);
|
|
134
120
|
margin-block-end: var(--spacing);
|
|
135
121
|
}
|
|
136
122
|
|
|
137
|
-
.Prose :is(h2, h3) + * {
|
|
123
|
+
.Prose :is(h2, h3):not(:global(.custom-component) :is(h2, h3)) + * {
|
|
138
124
|
--spacing: var(--base-size-40);
|
|
139
125
|
}
|
|
140
126
|
|
|
@@ -142,7 +128,7 @@
|
|
|
142
128
|
/* 5. Paragraphs */
|
|
143
129
|
/* ---------------------------------------------------------- */
|
|
144
130
|
|
|
145
|
-
.Prose p {
|
|
131
|
+
.Prose p:not(:global(.custom-component) p) {
|
|
146
132
|
--spacing: var(--base-size-24);
|
|
147
133
|
}
|
|
148
134
|
|
|
@@ -150,8 +136,8 @@
|
|
|
150
136
|
/* 6. Lists */
|
|
151
137
|
/* ---------------------------------------------------------- */
|
|
152
138
|
|
|
153
|
-
.Prose ul,
|
|
154
|
-
.Prose ol {
|
|
139
|
+
.Prose ul:not(:global(.custom-component) ul),
|
|
140
|
+
.Prose ol:not(:global(.custom-component) ol) {
|
|
155
141
|
--spacing: var(--base-size-16);
|
|
156
142
|
display: flex;
|
|
157
143
|
flex-direction: column;
|
|
@@ -161,12 +147,12 @@
|
|
|
161
147
|
line-height: var(--brand-text-lineHeight-300);
|
|
162
148
|
}
|
|
163
149
|
|
|
164
|
-
.Prose ul {
|
|
150
|
+
.Prose ul:not(:global(.custom-component) ul) {
|
|
165
151
|
list-style-type: image;
|
|
166
152
|
list-style-image: var(--brand-Prose-unorderedList-imageUrl);
|
|
167
153
|
}
|
|
168
154
|
|
|
169
|
-
.Prose li {
|
|
155
|
+
.Prose li:not(:global(.custom-component) li) {
|
|
170
156
|
--spacing: 0;
|
|
171
157
|
}
|
|
172
158
|
|
|
@@ -174,11 +160,11 @@
|
|
|
174
160
|
/* 7. Inline elements */
|
|
175
161
|
/* ---------------------------------------------------------- */
|
|
176
162
|
|
|
177
|
-
.Prose strong {
|
|
163
|
+
.Prose strong:not(:global(.custom-component) strong) {
|
|
178
164
|
font-weight: var(--brand-text-weight-800);
|
|
179
165
|
}
|
|
180
166
|
|
|
181
|
-
.Prose em {
|
|
167
|
+
.Prose em:not(:global(.custom-component) em) {
|
|
182
168
|
font-variation-settings: 'ital' 10;
|
|
183
169
|
font-synthesis: none;
|
|
184
170
|
}
|
|
@@ -215,7 +201,7 @@
|
|
|
215
201
|
border-color: var(--brand-InlineLink-color-pressed);
|
|
216
202
|
}
|
|
217
203
|
|
|
218
|
-
.Prose code {
|
|
204
|
+
.Prose code:not(:global(.custom-component) code) {
|
|
219
205
|
font-family: var(--brand-fontStack-monospace);
|
|
220
206
|
font-size: var(--brand-text-size-100);
|
|
221
207
|
white-space: break-spaces;
|
|
@@ -224,7 +210,7 @@
|
|
|
224
210
|
background-color: var(--base-color-scale-indigo-0);
|
|
225
211
|
}
|
|
226
212
|
|
|
227
|
-
[data-color-mode='dark'] .Prose code {
|
|
213
|
+
[data-color-mode='dark'] .Prose code:not(:global(.custom-component) code) {
|
|
228
214
|
background-color: var(--base-color-scale-indigo-9);
|
|
229
215
|
}
|
|
230
216
|
|
|
@@ -232,7 +218,7 @@
|
|
|
232
218
|
/* 8. Images */
|
|
233
219
|
/* ---------------------------------------------------------- */
|
|
234
220
|
|
|
235
|
-
.Prose img {
|
|
221
|
+
.Prose img:not(:global(.custom-component) img) {
|
|
236
222
|
--spacing: var(--brand-Prose-img-spacing);
|
|
237
223
|
display: block;
|
|
238
224
|
max-width: 100%;
|
|
@@ -244,7 +230,7 @@
|
|
|
244
230
|
overflow: hidden;
|
|
245
231
|
}
|
|
246
232
|
|
|
247
|
-
.Prose video {
|
|
233
|
+
.Prose video:not(:global(.custom-component) video) {
|
|
248
234
|
--spacing: var(--brand-Prose-img-spacing);
|
|
249
235
|
display: block;
|
|
250
236
|
max-width: 100%;
|
|
@@ -256,7 +242,7 @@
|
|
|
256
242
|
/* 9. Block elements */
|
|
257
243
|
/* ---------------------------------------------------------- */
|
|
258
244
|
|
|
259
|
-
.Prose blockquote {
|
|
245
|
+
.Prose blockquote:not(:global(.custom-component) blockquote) {
|
|
260
246
|
font-family: var(--brand-fontStack-sansSerif);
|
|
261
247
|
--spacing: var(--brand-Prose-blockquote-spacing);
|
|
262
248
|
position: relative;
|
|
@@ -264,11 +250,11 @@
|
|
|
264
250
|
line-height: var(--brand-text-lineHeight-400);
|
|
265
251
|
padding-top: var(--base-size-48);
|
|
266
252
|
padding-left: var(--base-size-40);
|
|
267
|
-
padding-bottom: var(--base-size-8);
|
|
253
|
+
padding-bottom: var (--base-size-8);
|
|
268
254
|
margin-bottom: var(--spacing);
|
|
269
255
|
}
|
|
270
256
|
|
|
271
|
-
.Prose blockquote::before {
|
|
257
|
+
.Prose blockquote:not(:global(.custom-component) blockquote)::before {
|
|
272
258
|
content: '“';
|
|
273
259
|
font-size: var(--base-size-48);
|
|
274
260
|
line-height: var(--base-size-64);
|
|
@@ -277,7 +263,7 @@
|
|
|
277
263
|
top: 0;
|
|
278
264
|
}
|
|
279
265
|
|
|
280
|
-
.Prose blockquote::after {
|
|
266
|
+
.Prose blockquote:not(:global(.custom-component) blockquote)::after {
|
|
281
267
|
content: '';
|
|
282
268
|
display: block;
|
|
283
269
|
position: absolute;
|
|
@@ -289,14 +275,14 @@
|
|
|
289
275
|
background-image: linear-gradient(180deg, var(--base-color-scale-blue-5), var(--base-color-scale-purple-5));
|
|
290
276
|
}
|
|
291
277
|
|
|
292
|
-
.Prose figure figcaption {
|
|
278
|
+
.Prose figure figcaption:not(:global(.custom-component) figure figcaption) {
|
|
293
279
|
font-family: var(--brand-fontStack-monospace);
|
|
294
280
|
font-size: var(--brand-text-size-100);
|
|
295
281
|
line-height: var(--brand-text-lineHeight-100);
|
|
296
282
|
color: var(--brand-color-text-muted);
|
|
297
283
|
}
|
|
298
284
|
|
|
299
|
-
.Prose hr {
|
|
285
|
+
.Prose hr:not(:global(.custom-component) hr) {
|
|
300
286
|
--spacing: var(--base-size-64);
|
|
301
287
|
border: 0;
|
|
302
288
|
height: 1px;
|
|
@@ -304,7 +290,61 @@
|
|
|
304
290
|
}
|
|
305
291
|
|
|
306
292
|
/**
|
|
307
|
-
* 10.
|
|
293
|
+
* 10. Tables
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
.Prose table:not(:global(.custom-component) table) {
|
|
297
|
+
width: 100%;
|
|
298
|
+
overflow: auto;
|
|
299
|
+
border-collapse: separate;
|
|
300
|
+
border-spacing: 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.Prose th:not(:global(.custom-component) th) {
|
|
304
|
+
font-weight: var(--brand-text-weight-600);
|
|
305
|
+
background-color: var(--brand-color-bg-subtle);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.Prose :is(th, td):not(:global(.custom-component) :is(th, td)) {
|
|
309
|
+
padding: var(--base-size-8) var(--base-size-16);
|
|
310
|
+
border-color: var(--brand-color-border-muted);
|
|
311
|
+
border-style: solid;
|
|
312
|
+
border-width: 0;
|
|
313
|
+
border-left-width: var(--brand-borderWidth-thin);
|
|
314
|
+
border-top-width: var(--brand-borderWidth-thin);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.Prose tr:last-child td:not(:global(.custom-component) tr:last-child td) {
|
|
318
|
+
border-bottom-width: var(--brand-borderWidth-thin);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.Prose tr :is(td, th):last-child:not(:global(.custom-component) tr :is(td, th):last-child) {
|
|
322
|
+
border-right-width: var(--brand-borderWidth-thin);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.Prose thead th:first-child:not(:global(.custom-component) thead th:first-child) {
|
|
326
|
+
border-top-left-radius: var(--brand-borderRadius-medium);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.Prose thead th:last-child:not(:global(.custom-component) thead th:last-child) {
|
|
330
|
+
border-top-right-radius: var(--brand-borderRadius-medium);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.Prose tbody tr:last-child td:last-child:not(:global(.custom-component) tbody tr:last-child td:last-child) {
|
|
334
|
+
border-bottom-right-radius: var(--brand-borderRadius-medium);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.Prose tbody tr:last-child td:first-child:not(:global(.custom-component) tbody tr:last-child td:first-child) {
|
|
338
|
+
border-bottom-left-radius: var(--brand-borderRadius-medium);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.Prose table img:not(:global(.custom-component) table img) {
|
|
342
|
+
background-color: transparent;
|
|
343
|
+
vertical-align: middle;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* 11. Custom stuff - Move out to separate stylesheet
|
|
308
348
|
*/
|
|
309
349
|
.customPageHero {
|
|
310
350
|
padding-top: 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/doctocat-nextjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-rc.c313ac3",
|
|
4
4
|
"description": "A Next.js theme for building Primer documentation sites",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"nextra": "^4.2.1",
|
|
28
28
|
"react": "18.3.1",
|
|
29
29
|
"react-dom": "18.3.1",
|
|
30
|
-
"react-focus-on": "3.9.4"
|
|
30
|
+
"react-focus-on": "3.9.4",
|
|
31
|
+
"react-live": "^4.1.8"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@github/prettier-config": "^0.0.6",
|