@primer/doctocat-nextjs 0.1.0 → 0.2.0-rc.10bf384
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 +8 -0
- package/components/content/caption/Caption.tsx +3 -3
- package/components/content/dos-and-donts/DosAndDonts.module.css +60 -0
- package/components/content/dos-and-donts/DosAndDonts.tsx +17 -44
- package/components/context/color-modes/ColorModeProvider.tsx +2 -2
- package/components/index.ts +9 -0
- package/components/layout/article/Article.module.css +8 -0
- package/components/layout/article/Article.tsx +24 -0
- package/components/layout/footer/Footer.module.css +0 -0
- package/components/layout/footer/Footer.tsx +41 -0
- package/components/layout/header/Header.tsx +10 -15
- package/components/layout/heading-link/HeadingLink.module.css +16 -0
- package/components/layout/heading-link/HeadingLinks.tsx +31 -0
- package/components/layout/nav-drawer/Drawer.tsx +7 -2
- package/components/layout/nav-drawer/NavDrawer.module.css +51 -0
- package/components/layout/nav-drawer/NavDrawer.tsx +16 -36
- package/components/layout/nav-drawer/useNavDrawerState.ts +1 -1
- package/components/layout/related-content-links/RelatedContentLinks.tsx +5 -4
- package/components/layout/related-content-links/getRelatedPages.tsx +57 -0
- package/components/layout/root-layout/Theme.tsx +144 -262
- package/components/layout/root-layout/index.tsx +11 -4
- package/components/layout/sidebar/Sidebar.tsx +72 -91
- package/components/layout/table-of-contents/TableOfContents.module.css +5 -0
- package/components/layout/table-of-contents/TableOfContents.tsx +5 -3
- package/components/layout/underline-nav/UnderlineNav.tsx +13 -4
- package/components/library.ts +3 -0
- package/css/prose.module.css +8 -0
- package/doctocat.config.js +4 -10
- package/helpers/hasChildren.ts +3 -3
- package/index.tsx +2 -6
- package/package.json +10 -9
- package/tsconfig.json +5 -3
- package/types.ts +20 -1
|
@@ -1,29 +1,32 @@
|
|
|
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} from 'nextra'
|
|
5
|
-
import {useRouter} from 'next/router'
|
|
6
|
-
import getConfig from 'next/config'
|
|
4
|
+
import {Folder, MdxFile, PageMapItem} from 'nextra'
|
|
7
5
|
|
|
8
6
|
import styles from './Sidebar.module.css'
|
|
9
7
|
import {LinkExternalIcon} from '@primer/octicons-react'
|
|
10
|
-
import type {DocsItem,
|
|
8
|
+
import type {DocsItem, ExtendedPageItem} from '../../../index'
|
|
11
9
|
import {hasChildren} from '../../../helpers/hasChildren'
|
|
10
|
+
import {usePathname} from 'next/navigation'
|
|
12
11
|
|
|
13
12
|
type SidebarProps = {
|
|
14
|
-
pageMap:
|
|
13
|
+
pageMap: PageMapItem[]
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const hasShowTabs = (child: DocsItem): boolean => {
|
|
16
|
+
const hasShowTabs = (child: ExtendedPageItem): boolean => {
|
|
20
17
|
return child.name === 'index' && (child as MdxFile).frontMatter?.['show-tabs'] === true
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
export function Sidebar({pageMap}: SidebarProps) {
|
|
24
|
-
const
|
|
20
|
+
export function Sidebar({pageMap: pageMapIn}: SidebarProps) {
|
|
21
|
+
const pageMap = pageMapIn as ExtendedPageItem[]
|
|
22
|
+
|
|
23
|
+
const pathname = usePathname()
|
|
25
24
|
|
|
26
|
-
const
|
|
25
|
+
const externalLinks = pageMap.filter(page => {
|
|
26
|
+
if (page.href && page.href.startsWith('http')) {
|
|
27
|
+
return page
|
|
28
|
+
}
|
|
29
|
+
})
|
|
27
30
|
|
|
28
31
|
/**
|
|
29
32
|
* Sorts the incoming data so that folders with a menu-position frontmatter value
|
|
@@ -33,11 +36,11 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
33
36
|
const reorderedPageMap = useMemo(
|
|
34
37
|
() =>
|
|
35
38
|
[...pageMap].sort((a, b) => {
|
|
36
|
-
if (hasChildren(a)
|
|
37
|
-
const aIndex = a.children.find(child => child.name === 'index'
|
|
39
|
+
if (hasChildren(a)) {
|
|
40
|
+
const aIndex = a.children.find(child => (child as MdxFile).name === 'index')
|
|
38
41
|
const aPosition = (aIndex as MdxFile | undefined)?.frontMatter?.['menu-position'] ?? Infinity
|
|
39
|
-
if (hasChildren(b)
|
|
40
|
-
const bIndex = b.children.find(child => child.name === 'index'
|
|
42
|
+
if (hasChildren(b)) {
|
|
43
|
+
const bIndex = b.children.find(child => (child as MdxFile).name === 'index')
|
|
41
44
|
const bPosition = (bIndex as MdxFile | undefined)?.frontMatter?.['menu-position'] ?? Infinity
|
|
42
45
|
return aPosition - bPosition
|
|
43
46
|
}
|
|
@@ -51,95 +54,73 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
51
54
|
<div className={styles.Sidebar}>
|
|
52
55
|
<NavList className={styles.NavList} aria-label="Menu links">
|
|
53
56
|
{reorderedPageMap.map(item => {
|
|
54
|
-
if (item.
|
|
57
|
+
if (item.hasOwnProperty('data')) return null
|
|
58
|
+
|
|
59
|
+
if (!hasChildren(item)) return null
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
const indexPage = (item as Folder).children.find(child => (child as MdxFile).name === 'index') as MdxFile
|
|
62
|
+
const subNavName = indexPage.frontMatter?.title ?? ''
|
|
63
|
+
const shouldShowTabs = indexPage.frontMatter?.['show-tabs'] ?? false
|
|
64
|
+
if (shouldShowTabs) {
|
|
57
65
|
return (
|
|
58
|
-
<NavList.Item as={NextLink} key={
|
|
59
|
-
{(
|
|
66
|
+
<NavList.Item as={NextLink} key={indexPage.name} href={indexPage.route}>
|
|
67
|
+
{(indexPage as MdxFile).frontMatter?.title || item.name}
|
|
60
68
|
</NavList.Item>
|
|
61
69
|
)
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
</NavList.Item>
|
|
74
|
-
)
|
|
75
|
-
}
|
|
72
|
+
return (
|
|
73
|
+
<NavList.Group title={subNavName} key={item.name} sx={{mb: 24}}>
|
|
74
|
+
{item.children
|
|
75
|
+
.sort((a, b) => ((a as MdxFile).name === 'index' ? -1 : (b as MdxFile).name === 'index' ? 1 : 0)) // puts index page first
|
|
76
|
+
// only show index page if it has show-tabs
|
|
77
|
+
.filter(child => (child as MdxFile).name !== 'index' || hasShowTabs(child as ExtendedPageItem))
|
|
78
|
+
.map(child => {
|
|
79
|
+
if (!hasChildren(child)) {
|
|
80
|
+
const {name, route} = child as MdxFile
|
|
76
81
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
as={NextLink}
|
|
89
|
-
key={child.name}
|
|
90
|
-
href={child.route}
|
|
91
|
-
sx={{textTransform: 'capitalize'}}
|
|
92
|
-
aria-current={child.route === router.pathname ? 'page' : undefined}
|
|
93
|
-
>
|
|
94
|
-
{child.title}
|
|
95
|
-
</NavList.Item>
|
|
96
|
-
)
|
|
97
|
-
}
|
|
82
|
+
return (
|
|
83
|
+
<NavList.Item
|
|
84
|
+
as={NextLink}
|
|
85
|
+
key={name}
|
|
86
|
+
href={route}
|
|
87
|
+
aria-current={route === pathname ? 'page' : undefined}
|
|
88
|
+
>
|
|
89
|
+
{(child as MdxFile).frontMatter?.title || name}
|
|
90
|
+
</NavList.Item>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
98
93
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
return (
|
|
105
|
-
<NavList.Item
|
|
106
|
-
as={NextLink}
|
|
107
|
-
key={(landingPageItem as MdxFile).route}
|
|
108
|
-
href={(landingPageItem as MdxFile).route}
|
|
109
|
-
sx={{textTransform: 'capitalize'}}
|
|
110
|
-
aria-current={(landingPageItem as MdxFile).route === router.pathname ? 'page' : undefined}
|
|
111
|
-
>
|
|
112
|
-
{(landingPageItem as MdxFile).frontMatter?.title || item.name}
|
|
113
|
-
</NavList.Item>
|
|
114
|
-
)
|
|
115
|
-
}
|
|
94
|
+
if (hasChildren(child)) {
|
|
95
|
+
const landingPageItem = (child as Folder).children.find(
|
|
96
|
+
innerChild => (innerChild as DocsItem).name === 'index',
|
|
97
|
+
)
|
|
116
98
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
99
|
+
return (
|
|
100
|
+
<NavList.Item
|
|
101
|
+
as={NextLink}
|
|
102
|
+
key={(landingPageItem as MdxFile).route}
|
|
103
|
+
href={(landingPageItem as MdxFile).route}
|
|
104
|
+
sx={{textTransform: 'capitalize'}}
|
|
105
|
+
aria-current={(landingPageItem as MdxFile).route === pathname ? 'page' : undefined}
|
|
106
|
+
>
|
|
107
|
+
{(landingPageItem as MdxFile).frontMatter?.title || item.name}
|
|
108
|
+
</NavList.Item>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
})}
|
|
112
|
+
</NavList.Group>
|
|
113
|
+
)
|
|
124
114
|
})}
|
|
125
|
-
{
|
|
115
|
+
{externalLinks.length > 0 && (
|
|
126
116
|
<NavList.Group title="" sx={{mb: 24}}>
|
|
127
|
-
{
|
|
128
|
-
const isExternalUrl = link.href.startsWith('http')
|
|
129
|
-
|
|
117
|
+
{externalLinks.map(link => {
|
|
130
118
|
return (
|
|
131
|
-
<NavList.Item
|
|
132
|
-
as={NextLink}
|
|
133
|
-
key={link.title}
|
|
134
|
-
href={link.href}
|
|
135
|
-
target={isExternalUrl ? '_blank' : undefined}
|
|
136
|
-
>
|
|
119
|
+
<NavList.Item as={NextLink} key={link.title} href={link.href}>
|
|
137
120
|
{link.title}
|
|
138
|
-
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
</NavList.TrailingVisual>
|
|
142
|
-
)}
|
|
121
|
+
<NavList.TrailingVisual>
|
|
122
|
+
<LinkExternalIcon />
|
|
123
|
+
</NavList.TrailingVisual>
|
|
143
124
|
</NavList.Item>
|
|
144
125
|
)
|
|
145
126
|
})}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
'use client'
|
|
1
2
|
import React, {useEffect, useMemo} from 'react'
|
|
2
3
|
import {NavList} from '@primer/react'
|
|
3
4
|
import {Text} from '@primer/react-brand'
|
|
4
5
|
import {Heading as HeadingType} from 'nextra'
|
|
6
|
+
import clsx from 'clsx'
|
|
5
7
|
|
|
6
8
|
import styles from './TableOfContents.module.css'
|
|
7
9
|
|
|
@@ -57,14 +59,14 @@ export function TableOfContents({headings}: TableOfContentsProps) {
|
|
|
57
59
|
if (!depth2Headings.length) return null
|
|
58
60
|
|
|
59
61
|
return (
|
|
60
|
-
<aside className={styles.wrapper}>
|
|
62
|
+
<aside className={clsx(styles.wrapper, 'exclude-from-prose', 'custom-component')}>
|
|
61
63
|
<Text as="p" size="100" variant="muted" weight="normal" className={styles.heading}>
|
|
62
64
|
On this page
|
|
63
65
|
</Text>
|
|
64
|
-
<NavList aria-label="Table of contents">
|
|
66
|
+
<NavList aria-label="Table of contents" className="custom-component">
|
|
65
67
|
{depth2Headings.map(heading => (
|
|
66
68
|
<NavList.Item
|
|
67
|
-
className={styles.item}
|
|
69
|
+
className={clsx(styles.item, 'custom-component')}
|
|
68
70
|
key={heading.id}
|
|
69
71
|
id={`toc-heading-${heading.id}`}
|
|
70
72
|
href={`#${heading.id}`}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, {useEffect, useState} from 'react'
|
|
2
2
|
import {UnderlineNav as PrimerUnderlineNav} from '@primer/react'
|
|
3
|
-
import {
|
|
3
|
+
import {usePathname} from 'next/navigation'
|
|
4
|
+
|
|
4
5
|
import Link from 'next/link'
|
|
5
6
|
import {MdxFile} from 'nextra'
|
|
6
7
|
|
|
@@ -9,8 +10,10 @@ type UnderlineNavProps = {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function UnderlineNav({tabData}: UnderlineNavProps) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
13
|
+
const [isClient, setIsClient] = useState(false)
|
|
14
|
+
const pathname = usePathname()
|
|
15
|
+
|
|
16
|
+
const currentRoute = pathname
|
|
14
17
|
|
|
15
18
|
// Reorders tabData so the tab with name === index is always first
|
|
16
19
|
if (tabData.length > 1) {
|
|
@@ -21,6 +24,12 @@ export function UnderlineNav({tabData}: UnderlineNavProps) {
|
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
setIsClient(true)
|
|
29
|
+
}, [])
|
|
30
|
+
|
|
31
|
+
if (!isClient) return null
|
|
32
|
+
|
|
24
33
|
return (
|
|
25
34
|
<PrimerUnderlineNav aria-label="Sibling pages">
|
|
26
35
|
{tabData.length > 1 &&
|
package/css/prose.module.css
CHANGED
|
@@ -244,6 +244,14 @@
|
|
|
244
244
|
overflow: hidden;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
.Prose video {
|
|
248
|
+
--spacing: var(--brand-Prose-img-spacing);
|
|
249
|
+
display: block;
|
|
250
|
+
max-width: 100%;
|
|
251
|
+
height: auto;
|
|
252
|
+
margin-block-start: var(--spacing);
|
|
253
|
+
}
|
|
254
|
+
|
|
247
255
|
/* ---------------------------------------------------------- */
|
|
248
256
|
/* 9. Block elements */
|
|
249
257
|
/* ---------------------------------------------------------- */
|
package/doctocat.config.js
CHANGED
|
@@ -1,29 +1,23 @@
|
|
|
1
1
|
import nextra from 'nextra'
|
|
2
|
-
import transpiler from 'next-transpile-modules'
|
|
3
2
|
|
|
4
3
|
const withNextra = nextra({
|
|
5
|
-
theme: '@primer/doctocat-nextjs',
|
|
6
4
|
staticImage: true,
|
|
7
5
|
})
|
|
8
6
|
|
|
9
|
-
const withTM = transpiler(['@primer/doctocat-nextjs'])
|
|
10
|
-
|
|
11
7
|
/*
|
|
12
8
|
* Wrapper for next config, that allows us to do some shared configuration
|
|
13
9
|
* Provides a default config, but allows overriding it
|
|
14
|
-
*
|
|
10
|
+
* Relies on `transpilePackages: ['@primer/doctocat-nextjs'],` being set in the next.config
|
|
15
11
|
*/
|
|
16
12
|
function withDoctocat(config = {}) {
|
|
17
|
-
return
|
|
13
|
+
return {
|
|
18
14
|
...withNextra(),
|
|
19
15
|
images: {
|
|
20
16
|
unoptimized: true,
|
|
21
17
|
},
|
|
22
|
-
|
|
23
|
-
siteTitle: config.publicRuntimeConfig.siteTitle || 'Doctocat', // to add a custom site title
|
|
24
|
-
},
|
|
18
|
+
|
|
25
19
|
...config,
|
|
26
|
-
}
|
|
20
|
+
}
|
|
27
21
|
}
|
|
28
22
|
|
|
29
23
|
export default withDoctocat
|
package/helpers/hasChildren.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {PageMapItem, Folder} from 'nextra'
|
|
2
|
-
import {DocsItem} from '../types'
|
|
3
2
|
|
|
4
|
-
export
|
|
5
|
-
'children' in item && Array.isArray(
|
|
3
|
+
export function hasChildren(item: PageMapItem): item is Folder {
|
|
4
|
+
return 'children' in item && Array.isArray(item.children)
|
|
5
|
+
}
|
package/index.tsx
CHANGED
|
@@ -2,15 +2,11 @@
|
|
|
2
2
|
* Root layout / theme (required)
|
|
3
3
|
*/
|
|
4
4
|
import Theme from './components/layout/root-layout/index'
|
|
5
|
-
|
|
5
|
+
export {generateStaticParamsFor, importPage} from 'nextra/pages'
|
|
6
|
+
export {getPageMap} from 'nextra/page-map'
|
|
6
7
|
export default Theme
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Types
|
|
10
11
|
*/
|
|
11
12
|
export * from './types'
|
|
12
|
-
/**
|
|
13
|
-
* Components
|
|
14
|
-
*/
|
|
15
|
-
export {DoDontContainer, Do, Dont} from './components/content/dos-and-donts/DosAndDonts'
|
|
16
|
-
export {Caption} from './components/content/caption/Caption'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/doctocat-nextjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-rc.10bf384",
|
|
4
4
|
"description": "A Next.js theme for building Primer documentation sites",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -17,16 +17,17 @@
|
|
|
17
17
|
"react-dom": "18.3.1"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@
|
|
21
|
-
"@primer/react": "
|
|
20
|
+
"@next/mdx": "^15.1.6",
|
|
21
|
+
"@primer/octicons-react": "19.15.0",
|
|
22
|
+
"@primer/react": "^37.11.0",
|
|
22
23
|
"@primer/react-brand": "0.46.0",
|
|
23
|
-
"
|
|
24
|
-
"framer-motion": "12.0
|
|
24
|
+
"@types/lodash.debounce": "^4.0.9",
|
|
25
|
+
"framer-motion": "12.4.0",
|
|
25
26
|
"lodash.debounce": "^4.0.8",
|
|
26
|
-
"
|
|
27
|
-
"nextra": "3.3.1",
|
|
27
|
+
"nextra": "^4.2.1",
|
|
28
28
|
"react": "18.3.1",
|
|
29
|
-
"react-dom": "18.3.1"
|
|
29
|
+
"react-dom": "18.3.1",
|
|
30
|
+
"react-focus-on": "3.9.4"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@github/prettier-config": "^0.0.6",
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
"@types/react-dom": "18.3.1",
|
|
36
37
|
"clsx": "2.1.1",
|
|
37
38
|
"next": "15.1.6",
|
|
38
|
-
"styled-components": "
|
|
39
|
+
"styled-components": "5.3.11",
|
|
39
40
|
"typescript": "5.7.3"
|
|
40
41
|
},
|
|
41
42
|
"overrides": {
|
package/tsconfig.json
CHANGED
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
"declaration": false,
|
|
6
6
|
"noEmit": true,
|
|
7
7
|
"esModuleInterop": true,
|
|
8
|
-
"strict":
|
|
8
|
+
"strict": true,
|
|
9
9
|
"skipLibCheck": true,
|
|
10
10
|
"allowJs": true,
|
|
11
11
|
"jsx": "react-jsx",
|
|
12
|
-
"moduleResolution": "
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
13
|
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
14
14
|
"resolveJsonModule": true,
|
|
15
|
-
"strictNullChecks": true
|
|
15
|
+
"strictNullChecks": true,
|
|
16
|
+
"strictFunctionTypes": true,
|
|
17
|
+
"noImplicitAny": true
|
|
16
18
|
}
|
|
17
19
|
}
|
package/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Folder, MdxFile} from 'nextra'
|
|
1
|
+
import {Folder, PageMapItem, MdxFile} from 'nextra'
|
|
2
2
|
|
|
3
3
|
export type ThemeConfig = {
|
|
4
4
|
docsRepositoryBase: string
|
|
@@ -8,6 +8,12 @@ export type ThemeConfig = {
|
|
|
8
8
|
}[]
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export type ExtendedPageItem = PageMapItem & {
|
|
12
|
+
name: string
|
|
13
|
+
title: string
|
|
14
|
+
href: string
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
export type FolderWithoutChildren = Omit<Folder, 'children'>
|
|
12
18
|
|
|
13
19
|
export type DocsItem = MdxFile & {
|
|
@@ -18,3 +24,16 @@ export type DocsItem = MdxFile & {
|
|
|
18
24
|
withIndexPage?: boolean
|
|
19
25
|
isUnderCurrentDocsTree?: boolean
|
|
20
26
|
}
|
|
27
|
+
|
|
28
|
+
export type FrontMatter = {
|
|
29
|
+
description?: string
|
|
30
|
+
filePath?: string
|
|
31
|
+
keywords?: string[]
|
|
32
|
+
related?: {
|
|
33
|
+
title: string
|
|
34
|
+
href: string
|
|
35
|
+
}[]
|
|
36
|
+
timestamp?: number
|
|
37
|
+
title?: string
|
|
38
|
+
[key: string]: unknown
|
|
39
|
+
}
|