Skip to content

Commit 0afdf66

Browse files
authored
Primer Update: Table of Contents (#22933)
* update to ActionList * fix nested mini tocs * adding key * remove li and fix tests * update font size to 14px * remove border radius
1 parent be52a49 commit 0afdf66

6 files changed

Lines changed: 54 additions & 34 deletions

File tree

components/article/ArticlePage.tsx

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useRouter } from 'next/router'
22
import cx from 'classnames'
3-
import { Heading } from '@primer/components'
3+
import { ActionList, Heading } from '@primer/components'
44

55
import { ZapIcon, InfoIcon, ShieldLockIcon } from '@primer/octicons-react'
66
import { Callout } from 'components/ui/Callout'
@@ -45,12 +45,19 @@ export const ArticlePage = () => {
4545

4646
const renderTocItem = (item: MiniTocItem) => {
4747
return (
48-
<li key={item.contents} className={cx(item.platform, 'mb-2 lh-condensed')}>
49-
<div className="mb-2 lh-condensed" dangerouslySetInnerHTML={{ __html: item.contents }} />
50-
{item.items && item.items.length > 0 ? (
51-
<ul className="list-style-none pl-0 f5 mb-0 ml-3">{item.items.map(renderTocItem)}</ul>
52-
) : null}
53-
</li>
48+
<ActionList.Item
49+
as="a"
50+
href={item.link}
51+
key={item.title}
52+
sx={{ listStyle: 'none', padding: '2px', fontSize: '14px' }}
53+
>
54+
<div className={cx(item.platform)}>
55+
{item.title}
56+
{item.items && item.items.length > 0 ? (
57+
<ul className="ml-3">{item.items.map(renderTocItem)}</ul>
58+
) : null}
59+
</div>
60+
</ActionList.Item>
5461
)
5562
}
5663

@@ -111,13 +118,18 @@ export const ArticlePage = () => {
111118
{miniTocItems.length > 1 && (
112119
<>
113120
<Heading as="h2" fontSize={1} id="in-this-article" className="mb-1">
114-
<a className="Link--primary" href="#in-this-article">
115-
{t('miniToc')}
116-
</a>
121+
<Link href="#in-this-article">{t('miniToc')}</Link>
117122
</Heading>
118-
<ul className="list-style-none pl-0 f5 mb-0">
119-
{miniTocItems.map(renderTocItem)}
120-
</ul>
123+
124+
<ActionList
125+
items={miniTocItems.map((items) => {
126+
return {
127+
key: title,
128+
text: title,
129+
renderItem: () => <ul>{renderTocItem(items)}</ul>,
130+
}
131+
})}
132+
/>
121133
</>
122134
)}
123135
</>

components/context/ArticleContext.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export type LearningTrack = {
99

1010
export type MiniTocItem = {
1111
platform: string
12-
contents: string
12+
title: string
13+
link: string
1314
items?: MiniTocItem[]
1415
}
1516

components/landing/CodeExampleCard.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { RepoIcon } from '@primer/octicons-react'
22
import { CodeExample } from 'components/context/ProductLandingContext'
33
import { TruncateLines } from 'components/ui/TruncateLines'
4+
import { Label } from '@primer/components'
45

56
type Props = {
67
example: CodeExample
@@ -21,12 +22,9 @@ export const CodeExampleCard = ({ example }: Props) => {
2122
<div className="d-flex flex-wrap">
2223
{example.tags.map((tag) => {
2324
return (
24-
<span
25-
key={tag}
26-
className="IssueLabel color-fg-on-emphasis color-bg-accent-emphasis mr-2 mb-1"
27-
>
25+
<Label key={tag} variant="small" sx={{ bg: 'accent.emphasis', mb: 1, mr: 2 }}>
2826
{tag}
29-
</span>
27+
</Label>
3028
)
3129
})}
3230
</div>

components/sublanding/ArticleCard.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ArticleGuide } from 'components/context/ProductSubLandingContext'
2+
import { Label } from '@primer/components'
23

34
type Props = {
45
card: ArticleGuide
@@ -18,13 +19,14 @@ export const ArticleCard = ({ card, typeLabel }: Props) => {
1819
<div>
1920
{card.topics.map((topic) => {
2021
return (
21-
<span
22-
data-testid="article-card-topic"
22+
<Label
2323
key={topic}
24-
className="IssueLabel color-bg-accent-emphasis color-fg-on-emphasis mr-1"
24+
data-testid="article-card-topic"
25+
variant="small"
26+
sx={{ bg: 'accent.emphasis', mr: 1 }}
2527
>
2628
{topic}
27-
</span>
29+
</Label>
2830
)
2931
})}
3032
</div>

lib/get-mini-toc-items.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default function getMiniTocItems(html, maxHeadingLevel = 2, headingScope
1212

1313
// return an array of objects containing each heading's contents, level, and optional platform.
1414
// Article layout uses these as follows:
15-
// - `contents` to render the mini TOC headings
15+
// - `title` and `link` to render the mini TOC headings
1616
// - `headingLevel` the `2` in `h2`; used for determining required indentation
1717
// - `platform` to show or hide platform-specific headings via client JS
1818

@@ -38,7 +38,8 @@ export default function getMiniTocItems(html, maxHeadingLevel = 2, headingScope
3838
// remove any <strong> tags but leave content
3939
$('strong', item).map((i, el) => $(el).replaceWith($(el).contents()))
4040

41-
const contents = `<a href="${href}">${$(item).html()}</a>`
41+
const link = href
42+
const title = $(item).html()
4243
const headingLevel = parseInt($(item)[0].name.match(/\d+/)[0], 10) || 0 // the `2` from `h2`
4344

4445
const platform = $(item).parent('.extended-markdown').attr('class') || ''
@@ -48,7 +49,7 @@ export default function getMiniTocItems(html, maxHeadingLevel = 2, headingScope
4849
mostImportantHeadingLevel = headingLevel
4950
}
5051

51-
return { contents, headingLevel, platform }
52+
return { link, title, headingLevel, platform }
5253
})
5354
.map((item) => {
5455
// set the indentation level for each item based on the most important

tests/rendering/server.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -328,16 +328,16 @@ describe('server', () => {
328328
test('renders mini TOC in articles with more than one heading', async () => {
329329
const $ = await getDOM('/en/github/getting-started-with-github/githubs-products')
330330
expect($('h2#in-this-article').length).toBe(1)
331-
expect($('h2#in-this-article + ul li a').length).toBeGreaterThan(1)
331+
expect($('h2#in-this-article + div div ul').length).toBeGreaterThan(1)
332332
})
333333

334334
test('renders mini TOC in articles that includes h3s when specified by frontmatter', async () => {
335335
const $ = await getDOM(
336336
'/en/admin/policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-security-settings-in-your-enterprise'
337337
)
338338
expect($('h2#in-this-article').length).toBe(1)
339-
expect($('h2#in-this-article + ul li').length).toBeGreaterThan(0) // non-indented items
340-
expect($('h2#in-this-article + ul li ul.ml-3').length).toBeGreaterThan(0) // indented items
339+
expect($('h2#in-this-article + div div ul').length).toBeGreaterThan(0) // non-indented items
340+
expect($('h2#in-this-article + div div ul a div div div ul.ml-3').length).toBeGreaterThan(0) // indented items
341341
})
342342

343343
test('does not render mini TOC in articles with only one heading', async () => {
@@ -361,14 +361,14 @@ describe('server', () => {
361361
const $ = await getDOM(
362362
'/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates'
363363
)
364-
expect($('h2#in-this-article + ul li a[href="#package-ecosystem"]').length).toBe(1)
364+
expect($('h2#in-this-article + div div ul a[href="#package-ecosystem"]').length).toBe(1)
365365
})
366366

367367
test('renders mini TOC with correct links when headings contain markup in localized content', async () => {
368368
const $ = await getDOM(
369369
'/ja/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates'
370370
)
371-
expect($('h2#in-this-article + ul li a[href="#package-ecosystem"]').length).toBe(1)
371+
expect($('h2#in-this-article + div div ul a[href="#package-ecosystem"]').length).toBe(1)
372372
})
373373
})
374374

@@ -878,9 +878,15 @@ describe('extended Markdown', () => {
878878
test('renders expected mini TOC headings in platform-specific content', async () => {
879879
const $ = await getDOM('/en/github/using-git/associating-text-editors-with-git')
880880
expect($('h2#in-this-article').length).toBe(1)
881-
expect($('h2#in-this-article + ul li.extended-markdown.mac').length).toBeGreaterThan(1)
882-
expect($('h2#in-this-article + ul li.extended-markdown.windows').length).toBeGreaterThan(1)
883-
expect($('h2#in-this-article + ul li.extended-markdown.linux').length).toBeGreaterThan(1)
881+
expect(
882+
$('h2#in-this-article + div div ul a div div div.extended-markdown.mac').length
883+
).toBeGreaterThan(1)
884+
expect(
885+
$('h2#in-this-article + div div ul a div div div.extended-markdown.windows').length
886+
).toBeGreaterThan(1)
887+
expect(
888+
$('h2#in-this-article + div div ul a div div div.extended-markdown.linux').length
889+
).toBeGreaterThan(1)
884890
})
885891
})
886892

0 commit comments

Comments
 (0)