Skip to content

Commit d76c16d

Browse files
authored
Scope markdown body (github#21082)
* update article content to markdown ui component * decouple lunr indexing from class name * remove summary outline none rule, apply utility class instead * improve typing * scope more styles down to markdown-body/extended-markdown * move all markdown-body style overrides to MarkdownContent component * fix class targeting within css module * clean up MarkdownContent header style * rename data-lunr to data-search * fix: inline code color issue * fix: update article markdown to work with MarkdownContent
1 parent 0e31d4a commit d76c16d

35 files changed

+472
-449
lines changed

components/TruncateLines.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
import React, { ReactNode, ReactHTML } from 'react'
1+
import React, { ReactNode } from 'react'
22
import cx from 'classnames'
33

44
type Props = {
5-
as?: keyof ReactHTML
5+
as?: keyof JSX.IntrinsicElements
66
maxLines: number
77
children: ReactNode
88
className?: string
99
}
1010
export const TruncateLines = (props: Props) => {
11-
const { as, maxLines, className, children } = props
12-
const Component = as || 'div'
11+
const { maxLines, className, children, as: Component = 'div' } = props
1312
return (
1413
<Component className={cx('root', className)}>
1514
{children}

components/article/ArticleContent.tsx

-18
This file was deleted.

components/article/ArticleGridLayout.tsx

+3-6
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,9 @@ export const ArticleGridLayout = ({ head, toc, children, className }: Props) =>
2222
)}
2323

2424
{/* content */}
25-
{/*
26-
NOTE: The article-grid-body class is used by the LUNR search scripts.
27-
If this class changes, please also change
28-
updating script/search/parse-page-sections-into-records.js.
29-
*/}
30-
<div className={cx(styles.content, 'article-grid-body')}>{children}</div>
25+
<div data-search="article-body" className={styles.content}>
26+
{children}
27+
</div>
3128
</div>
3229
)
3330
}

components/article/ArticlePage.tsx

+5-8
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { ArticleTitle } from 'components/article/ArticleTitle'
1111
import { useArticleContext } from 'components/context/ArticleContext'
1212
import { useTranslation } from 'components/hooks/useTranslation'
1313
import { LearningTrackNav } from './LearningTrackNav'
14-
import { ArticleContent } from './ArticleContent'
14+
import { MarkdownContent } from 'components/ui/MarkdownContent'
1515
import { ArticleGridLayout } from './ArticleGridLayout'
1616

1717
// Mapping of a "normal" article to it's interactive counterpart
@@ -63,12 +63,7 @@ export const ArticlePage = () => {
6363
</Callout>
6464
)}
6565

66-
{intro && (
67-
<div
68-
className="lead-mktg markdown-body mb-3"
69-
dangerouslySetInnerHTML={{ __html: intro }}
70-
/>
71-
)}
66+
{intro && <MarkdownContent className="lead-mktg mb-3">{intro}</MarkdownContent>}
7267

7368
{permissions && (
7469
<div
@@ -153,7 +148,9 @@ export const ArticlePage = () => {
153148
</>
154149
}
155150
>
156-
<ArticleContent>{renderedPage}</ArticleContent>
151+
<div id="article-contents">
152+
<MarkdownContent>{renderedPage}</MarkdownContent>
153+
</div>
157154
</ArticleGridLayout>
158155

159156
{currentLearningTrack?.trackName ? (

components/article/ArticleVersionPicker.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const ArticleVersionPicker = () => {
2525
`}
2626
data-testid="article-version-picker"
2727
>
28-
<summary className="f4 h5-mktg btn-outline-mktg btn-mktg p-2">
28+
<summary className="f4 h5-mktg btn-outline-mktg btn-mktg p-2 outline-none">
2929
<span className="d-md-none d-xl-inline-block">{t('article_version')}</span>{' '}
3030
{allVersions[currentVersion].versionTitle}
3131
<Dropdown.Caret />

components/landing/HomepageVersionPicker.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const HomepageVersionPicker = ({ variant }: Props) => {
2525
if (variant === 'inline') {
2626
return (
2727
<Details {...getDetailsProps()} className="details-reset">
28-
<summary aria-label="Toggle language list">
28+
<summary className="outline-none" aria-label="Toggle language list">
2929
<div className="d-flex flex-items-center flex-justify-between py-2">
3030
<span>{label}</span>
3131
<ChevronDownIcon size={24} className="arrow ml-md-1" />

components/landing/TocLanding.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { TableOfContents } from 'components/landing/TableOfContents'
33
import { useTocLandingContext } from 'components/context/TocLandingContext'
44
import { ArticleTopper } from 'components/article/ArticleTopper'
55
import { ArticleTitle } from 'components/article/ArticleTitle'
6-
import { ArticleContent } from 'components/article/ArticleContent'
6+
import { MarkdownContent } from 'components/ui/MarkdownContent'
77
import { ArticleList } from 'components/landing/ArticleList'
88
import { useTranslation } from 'components/hooks/useTranslation'
99
import { ArticleGridLayout } from 'components/article/ArticleGridLayout'
@@ -55,7 +55,11 @@ export const TocLanding = () => {
5555
</div>
5656
)}
5757

58-
{renderedPage && <ArticleContent>{renderedPage}</ArticleContent>}
58+
{renderedPage && (
59+
<div id="article-contents">
60+
<MarkdownContent>{renderedPage}</MarkdownContent>
61+
</div>
62+
)}
5963

6064
<TableOfContents items={tocItems} variant={variant} />
6165
</div>

components/lib/display-platform-specific-content.ts

+7-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import parseUserAgent from './user-agent'
33
import { sendEvent, EventType } from './events'
44

55
const supportedPlatforms = ['mac', 'windows', 'linux']
6-
const detectedPlatforms = new Set()
6+
const detectedPlatforms = new Set<string>()
77

88
// Emphasize content for the visitor's OS (inferred from user agent string)
99

@@ -66,9 +66,7 @@ function setActiveSwitcherLinks(platform: string) {
6666
function showPlatformSpecificContent(platform: string) {
6767
// find all platform-specific *block* elements and hide or show as appropriate
6868
// example: {{ #mac }} block content {{/mac}}
69-
const markdowns = Array.from(
70-
document.querySelectorAll('.extended-markdown')
71-
) as Array<HTMLElement>
69+
const markdowns = Array.from(document.querySelectorAll<HTMLElement>('.extended-markdown'))
7270
markdowns
7371
.filter((el) => supportedPlatforms.some((platform) => el.classList.contains(platform)))
7472
.forEach((el) => {
@@ -78,8 +76,8 @@ function showPlatformSpecificContent(platform: string) {
7876
// find all platform-specific *inline* elements and hide or show as appropriate
7977
// example: <span class="platform-mac">inline content</span>
8078
const platforms = Array.from(
81-
document.querySelectorAll('.platform-mac, .platform-windows, .platform-linux')
82-
) as Array<HTMLElement>
79+
document.querySelectorAll<HTMLElement>('.platform-mac, .platform-windows, .platform-linux')
80+
)
8381
platforms.forEach((el) => {
8482
el.style.display = el.classList.contains('platform-' + platform) ? '' : 'none'
8583
})
@@ -108,11 +106,11 @@ function getDetectedPlatforms(): Array<string> {
108106
// find all platform-specific *inline* elements and hide or show as appropriate
109107
// example: <span class="platform-mac">inline content</span>
110108
const platformEls = Array.from(
111-
document.querySelectorAll('.platform-mac, .platform-windows, .platform-linux')
112-
) as Array<HTMLElement>
109+
document.querySelectorAll<HTMLElement>('.platform-mac, .platform-windows, .platform-linux')
110+
)
113111
platformEls.forEach((el) => detectPlatforms(el))
114112

115-
return Array.from(detectedPlatforms) as Array<string>
113+
return Array.from(detectedPlatforms)
116114
}
117115

118116
function detectPlatforms(el: HTMLElement) {

components/page-header/LanguagePicker.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const LanguagePicker = ({ variant }: Props) => {
2020
if (variant === 'inline') {
2121
return (
2222
<Details {...getDetailsProps()} className="details-reset">
23-
<summary aria-label="Toggle language list">
23+
<summary className="outline-none" aria-label="Toggle language list">
2424
<div className="d-flex flex-items-center flex-justify-between py-2">
2525
<span>{selectedLang.nativeName || selectedLang.name}</span>
2626
<ChevronDownIcon size={24} className="arrow ml-md-1" />

components/page-header/ProductPicker.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export const ProductPicker = () => {
1313

1414
return (
1515
<Details {...getDetailsProps()} className="details-reset">
16-
<summary className="color-text-link" role="button" aria-label="Toggle products list">
16+
<summary
17+
className="color-text-link outline-none"
18+
role="button"
19+
aria-label="Toggle products list"
20+
>
1721
<div id="current-product" className="d-flex flex-items-center flex-justify-between py-2">
1822
{/* <!-- Product switcher - GitHub.com, Enterprise Server, etc -->
1923
<!-- 404 and 500 error layouts are not real pages so we need to hardcode the name for those --> */}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.articleMarkdown {
2+
pre {
3+
padding: 0;
4+
background-color: unset;
5+
}
6+
7+
table {
8+
table-layout: fixed !important;
9+
}
10+
}
+32-25
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import React from 'react'
2+
import cx from 'classnames'
23
import { useTheme } from '@primer/components'
34
import ReactMarkdown from 'react-markdown'
45
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
56
import { vs, vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'
67
import gfm from 'remark-gfm'
78

9+
import { MarkdownContent } from 'components/ui/MarkdownContent'
10+
11+
import styles from './ArticleMarkdown.module.scss'
12+
813
type Props = {
914
className?: string
1015
children: string
@@ -13,30 +18,32 @@ export const ArticleMarkdown = ({ className, children }: Props) => {
1318
const theme = useTheme()
1419

1520
return (
16-
<ReactMarkdown
17-
className={className}
18-
remarkPlugins={[gfm as any]}
19-
components={{
20-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
21-
code: ({ node, inline, className, children, ...props }) => {
22-
const match = /language-(\w+)/.exec(className || '')
23-
return !inline && match ? (
24-
<SyntaxHighlighter
25-
style={theme.colorScheme === 'dark' ? vscDarkPlus : vs}
26-
language={match[1]}
27-
PreTag="div"
28-
children={String(children).replace(/\n$/, '')}
29-
{...(props as any)}
30-
/>
31-
) : (
32-
<code className={className} {...props}>
33-
{children}
34-
</code>
35-
)
36-
},
37-
}}
38-
>
39-
{children}
40-
</ReactMarkdown>
21+
<MarkdownContent>
22+
<ReactMarkdown
23+
className={cx(styles.articleMarkdown, className)}
24+
remarkPlugins={[gfm as any]}
25+
components={{
26+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
27+
code: ({ node, inline, className, children, ...props }) => {
28+
const match = /language-(\w+)/.exec(className || '')
29+
return !inline && match ? (
30+
<SyntaxHighlighter
31+
style={theme.colorScheme === 'dark' ? vscDarkPlus : vs}
32+
language={match[1]}
33+
PreTag="div"
34+
children={String(children).replace(/\n$/, '')}
35+
{...(props as any)}
36+
/>
37+
) : (
38+
<code className={className} {...props}>
39+
{children}
40+
</code>
41+
)
42+
},
43+
}}
44+
>
45+
{children}
46+
</ReactMarkdown>
47+
</MarkdownContent>
4148
)
4249
}

components/release-notes/GHAEReleaseNotes.tsx

+18-15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import cx from 'classnames'
33
import { ChevronDownIcon } from '@primer/octicons-react'
44
import { GHAEReleaseNotePatch } from './GHAEReleaseNotePatch'
55
import { GHAEReleaseNotesContextT } from './types'
6+
import { MarkdownContent } from 'components/ui/MarkdownContent'
67

78
type GitHubAEProps = {
89
context: GHAEReleaseNotesContextT
@@ -20,7 +21,7 @@ export function GHAEReleaseNotes({ context }: GitHubAEProps) {
2021
<div></div>
2122
</div>
2223

23-
<div className="markdown-body">
24+
<MarkdownContent data-search="article-content">
2425
{releaseNotes.map((patch) => {
2526
return (
2627
<GHAEReleaseNotePatch
@@ -30,25 +31,27 @@ export function GHAEReleaseNotes({ context }: GitHubAEProps) {
3031
/>
3132
)
3233
})}
33-
</div>
34+
</MarkdownContent>
3435
</article>
3536

3637
<aside
37-
className="markdown-body position-sticky top-0 d-none d-md-block border-left no-print color-bg-primary flex-shrink-0"
38+
className="position-sticky top-0 d-none d-md-block border-left no-print color-bg-primary flex-shrink-0"
3839
style={{ width: 260, height: '100vh' }}
3940
>
4041
<nav className="height-full overflow-auto">
41-
<ul className="list-style-none pl-0 text-bold">
42-
{releases.map((release) => {
43-
return (
44-
<CollapsibleReleaseSection
45-
key={release.version}
46-
release={release}
47-
focusedPatch={focusedPatch}
48-
/>
49-
)
50-
})}
51-
</ul>
42+
<MarkdownContent data-search="article-content">
43+
<ul className="list-style-none pl-0 text-bold">
44+
{releases.map((release) => {
45+
return (
46+
<CollapsibleReleaseSection
47+
key={release.version}
48+
release={release}
49+
focusedPatch={focusedPatch}
50+
/>
51+
)
52+
})}
53+
</ul>
54+
</MarkdownContent>
5255
</nav>
5356
</aside>
5457
</div>
@@ -78,7 +81,7 @@ const CollapsibleReleaseSection = ({
7881
open={defaultIsOpen}
7982
onToggle={onToggle}
8083
>
81-
<summary className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between">
84+
<summary className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between outline-none">
8285
{release.version}
8386
<div className="d-flex">
8487
<span className="color-text-tertiary text-mono text-small text-normal mr-1">

0 commit comments

Comments
 (0)