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
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import cx from 'classnames'
|
||||
import { Heading } from '@primer/components'
|
||||
import { ActionList, Heading } from '@primer/components'
|
||||
|
||||
import { ZapIcon, InfoIcon, ShieldLockIcon } from '@primer/octicons-react'
|
||||
import { Callout } from 'components/ui/Callout'
|
||||
@@ -45,12 +45,19 @@ export const ArticlePage = () => {
|
||||
|
||||
const renderTocItem = (item: MiniTocItem) => {
|
||||
return (
|
||||
<li key={item.contents} className={cx(item.platform, 'mb-2 lh-condensed')}>
|
||||
<div className="mb-2 lh-condensed" dangerouslySetInnerHTML={{ __html: item.contents }} />
|
||||
<ActionList.Item
|
||||
as="a"
|
||||
href={item.link}
|
||||
key={item.title}
|
||||
sx={{ listStyle: 'none', padding: '2px', fontSize: '14px' }}
|
||||
>
|
||||
<div className={cx(item.platform)}>
|
||||
{item.title}
|
||||
{item.items && item.items.length > 0 ? (
|
||||
<ul className="list-style-none pl-0 f5 mb-0 ml-3">{item.items.map(renderTocItem)}</ul>
|
||||
<ul className="ml-3">{item.items.map(renderTocItem)}</ul>
|
||||
) : null}
|
||||
</li>
|
||||
</div>
|
||||
</ActionList.Item>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -111,13 +118,18 @@ export const ArticlePage = () => {
|
||||
{miniTocItems.length > 1 && (
|
||||
<>
|
||||
<Heading as="h2" fontSize={1} id="in-this-article" className="mb-1">
|
||||
<a className="Link--primary" href="#in-this-article">
|
||||
{t('miniToc')}
|
||||
</a>
|
||||
<Link href="#in-this-article">{t('miniToc')}</Link>
|
||||
</Heading>
|
||||
<ul className="list-style-none pl-0 f5 mb-0">
|
||||
{miniTocItems.map(renderTocItem)}
|
||||
</ul>
|
||||
|
||||
<ActionList
|
||||
items={miniTocItems.map((items) => {
|
||||
return {
|
||||
key: title,
|
||||
text: title,
|
||||
renderItem: () => <ul>{renderTocItem(items)}</ul>,
|
||||
}
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -9,7 +9,8 @@ export type LearningTrack = {
|
||||
|
||||
export type MiniTocItem = {
|
||||
platform: string
|
||||
contents: string
|
||||
title: string
|
||||
link: string
|
||||
items?: MiniTocItem[]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { RepoIcon } from '@primer/octicons-react'
|
||||
import { CodeExample } from 'components/context/ProductLandingContext'
|
||||
import { TruncateLines } from 'components/ui/TruncateLines'
|
||||
import { Label } from '@primer/components'
|
||||
|
||||
type Props = {
|
||||
example: CodeExample
|
||||
@@ -21,12 +22,9 @@ export const CodeExampleCard = ({ example }: Props) => {
|
||||
<div className="d-flex flex-wrap">
|
||||
{example.tags.map((tag) => {
|
||||
return (
|
||||
<span
|
||||
key={tag}
|
||||
className="IssueLabel color-fg-on-emphasis color-bg-accent-emphasis mr-2 mb-1"
|
||||
>
|
||||
<Label key={tag} variant="small" sx={{ bg: 'accent.emphasis', mb: 1, mr: 2 }}>
|
||||
{tag}
|
||||
</span>
|
||||
</Label>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ArticleGuide } from 'components/context/ProductSubLandingContext'
|
||||
import { Label } from '@primer/components'
|
||||
|
||||
type Props = {
|
||||
card: ArticleGuide
|
||||
@@ -18,13 +19,14 @@ export const ArticleCard = ({ card, typeLabel }: Props) => {
|
||||
<div>
|
||||
{card.topics.map((topic) => {
|
||||
return (
|
||||
<span
|
||||
data-testid="article-card-topic"
|
||||
<Label
|
||||
key={topic}
|
||||
className="IssueLabel color-bg-accent-emphasis color-fg-on-emphasis mr-1"
|
||||
data-testid="article-card-topic"
|
||||
variant="small"
|
||||
sx={{ bg: 'accent.emphasis', mr: 1 }}
|
||||
>
|
||||
{topic}
|
||||
</span>
|
||||
</Label>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ export default function getMiniTocItems(html, maxHeadingLevel = 2, headingScope
|
||||
|
||||
// return an array of objects containing each heading's contents, level, and optional platform.
|
||||
// Article layout uses these as follows:
|
||||
// - `contents` to render the mini TOC headings
|
||||
// - `title` and `link` to render the mini TOC headings
|
||||
// - `headingLevel` the `2` in `h2`; used for determining required indentation
|
||||
// - `platform` to show or hide platform-specific headings via client JS
|
||||
|
||||
@@ -38,7 +38,8 @@ export default function getMiniTocItems(html, maxHeadingLevel = 2, headingScope
|
||||
// remove any <strong> tags but leave content
|
||||
$('strong', item).map((i, el) => $(el).replaceWith($(el).contents()))
|
||||
|
||||
const contents = `<a href="${href}">${$(item).html()}</a>`
|
||||
const link = href
|
||||
const title = $(item).html()
|
||||
const headingLevel = parseInt($(item)[0].name.match(/\d+/)[0], 10) || 0 // the `2` from `h2`
|
||||
|
||||
const platform = $(item).parent('.extended-markdown').attr('class') || ''
|
||||
@@ -48,7 +49,7 @@ export default function getMiniTocItems(html, maxHeadingLevel = 2, headingScope
|
||||
mostImportantHeadingLevel = headingLevel
|
||||
}
|
||||
|
||||
return { contents, headingLevel, platform }
|
||||
return { link, title, headingLevel, platform }
|
||||
})
|
||||
.map((item) => {
|
||||
// set the indentation level for each item based on the most important
|
||||
|
||||
@@ -328,7 +328,7 @@ describe('server', () => {
|
||||
test('renders mini TOC in articles with more than one heading', async () => {
|
||||
const $ = await getDOM('/en/github/getting-started-with-github/githubs-products')
|
||||
expect($('h2#in-this-article').length).toBe(1)
|
||||
expect($('h2#in-this-article + ul li a').length).toBeGreaterThan(1)
|
||||
expect($('h2#in-this-article + div div ul').length).toBeGreaterThan(1)
|
||||
})
|
||||
|
||||
test('renders mini TOC in articles that includes h3s when specified by frontmatter', async () => {
|
||||
@@ -336,8 +336,8 @@ describe('server', () => {
|
||||
'/en/admin/policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-security-settings-in-your-enterprise'
|
||||
)
|
||||
expect($('h2#in-this-article').length).toBe(1)
|
||||
expect($('h2#in-this-article + ul li').length).toBeGreaterThan(0) // non-indented items
|
||||
expect($('h2#in-this-article + ul li ul.ml-3').length).toBeGreaterThan(0) // indented items
|
||||
expect($('h2#in-this-article + div div ul').length).toBeGreaterThan(0) // non-indented items
|
||||
expect($('h2#in-this-article + div div ul a div div div ul.ml-3').length).toBeGreaterThan(0) // indented items
|
||||
})
|
||||
|
||||
test('does not render mini TOC in articles with only one heading', async () => {
|
||||
@@ -361,14 +361,14 @@ describe('server', () => {
|
||||
const $ = await getDOM(
|
||||
'/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates'
|
||||
)
|
||||
expect($('h2#in-this-article + ul li a[href="#package-ecosystem"]').length).toBe(1)
|
||||
expect($('h2#in-this-article + div div ul a[href="#package-ecosystem"]').length).toBe(1)
|
||||
})
|
||||
|
||||
test('renders mini TOC with correct links when headings contain markup in localized content', async () => {
|
||||
const $ = await getDOM(
|
||||
'/ja/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates'
|
||||
)
|
||||
expect($('h2#in-this-article + ul li a[href="#package-ecosystem"]').length).toBe(1)
|
||||
expect($('h2#in-this-article + div div ul a[href="#package-ecosystem"]').length).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -878,9 +878,15 @@ describe('extended Markdown', () => {
|
||||
test('renders expected mini TOC headings in platform-specific content', async () => {
|
||||
const $ = await getDOM('/en/github/using-git/associating-text-editors-with-git')
|
||||
expect($('h2#in-this-article').length).toBe(1)
|
||||
expect($('h2#in-this-article + ul li.extended-markdown.mac').length).toBeGreaterThan(1)
|
||||
expect($('h2#in-this-article + ul li.extended-markdown.windows').length).toBeGreaterThan(1)
|
||||
expect($('h2#in-this-article + ul li.extended-markdown.linux').length).toBeGreaterThan(1)
|
||||
expect(
|
||||
$('h2#in-this-article + div div ul a div div div.extended-markdown.mac').length
|
||||
).toBeGreaterThan(1)
|
||||
expect(
|
||||
$('h2#in-this-article + div div ul a div div div.extended-markdown.windows').length
|
||||
).toBeGreaterThan(1)
|
||||
expect(
|
||||
$('h2#in-this-article + div div ul a div div div.extended-markdown.linux').length
|
||||
).toBeGreaterThan(1)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user