From 0de49c3661ef5301e7a9bba1f8b96fa846ef8831 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Fri, 25 Mar 2022 21:47:13 +0300 Subject: [PATCH] feat(theme-classic): allow line numbering to code blocks --- .../src/theme-classic.d.ts | 1 + .../src/theme/CodeBlock/index.tsx | 19 ++++++++-- .../src/theme/CodeBlock/styles.module.css | 28 ++++++++++++++- packages/docusaurus-theme-common/src/index.ts | 1 + .../src/utils/codeBlockUtils.ts | 4 +++ .../markdown-features-code-blocks.mdx | 36 ++++++++++++++++--- 6 files changed, 82 insertions(+), 7 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index b010f0038594..53b5fd3c3b42 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -121,6 +121,7 @@ declare module '@theme/CodeBlock' { readonly metastring?: string; readonly title?: string; readonly language?: string; + readonly showLineNumbers?: boolean; } export default function CodeBlock(props: Props): JSX.Element; diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx index 943d3f84676e..136655004519 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx @@ -13,6 +13,7 @@ import { parseCodeBlockTitle, parseLanguage, parseLines, + containsLineNumbers, ThemeClassNames, usePrismTheme, } from '@docusaurus/theme-common'; @@ -26,6 +27,7 @@ export default function CodeBlock({ className: blockClassName = '', metastring, title, + showLineNumbers, language: languageProp, }: Props): JSX.Element { const {prism} = useThemeConfig(); @@ -87,6 +89,8 @@ export default function CodeBlock({ const language = languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage; const {highlightLines, code} = parseLines(content, metastring, language); + const shouldShowLineNumbers = + showLineNumbers || containsLineNumbers(metastring); return ( - + {tokens.map((line, i) => { if (line.length === 1 && line[0]!.content === '\n') { line[0]!.content = ''; } - const lineProps = getLineProps({line, key: i}); + const lineProps = getLineProps({ + line, + key: i, + ...(shouldShowLineNumbers && {className: styles.codeLine}), + }); if (highlightLines.includes(i)) { lineProps.className += ' docusaurus-highlight-code-line'; @@ -132,6 +144,9 @@ export default function CodeBlock({ return ( + {shouldShowLineNumbers && ( + + )} {line.map((token, key) => ( ))} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css index fcdcca6b1c09..45ef6263e9c3 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css @@ -30,7 +30,7 @@ margin: 0; padding: 0; border-radius: var(--ifm-global-radius); - background-color: inherit; + --ifm-pre-background: inherit; } .codeBlockTitle + .codeBlockContent .codeBlock { @@ -45,14 +45,40 @@ .codeBlockLines { font: inherit; + background: var(--ifm-pre-background); /* rtl:ignore */ float: left; min-width: 100%; padding: var(--ifm-pre-padding); } +.codeBlockLinesWithNumbering { + padding-left: 0; +} + @media print { .codeBlockLines { white-space: pre-wrap; } } + +.codeLine { + counter-increment: line-count; +} + +.codeLineNumber { + display: inline-block; + position: sticky; + left: 0; + padding: 0 var(--ifm-pre-padding); + background: var(--ifm-pre-background); +} + +.codeLineNumber::before { + content: counter(line-count); + opacity: 0.4; +} + +:global(.docusaurus-highlight-code-line) .codeLineNumber::before { + opacity: 0.8; +} diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index a823af8d4220..2f7114977613 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -34,6 +34,7 @@ export { parseCodeBlockTitle, parseLanguage, parseLines, + containsLineNumbers, } from './utils/codeBlockUtils'; export { diff --git a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts index 8b89983bcbac..0ce49edf203f 100644 --- a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts @@ -71,6 +71,10 @@ export function parseCodeBlockTitle(metastring?: string): string { return metastring?.match(codeBlockTitleRegex)?.groups!.title ?? ''; } +export function containsLineNumbers(metastring?: string): boolean { + return metastring?.includes('showLineNumbers') || false; +} + /** * Gets the language name from the class name (set by MDX). * e.g. `"language-javascript"` => `"javascript"`. diff --git a/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx b/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx index 085d944ca429..7a25ae9822a2 100644 --- a/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx +++ b/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx @@ -32,6 +32,28 @@ function HelloCodeTitle(props) { +## Code line numbering + +You can enable line numbering for your code block by using `showLineNumbers` key within the language meta string (don't forget to add space directly before the key). + +````md +```jsx showLineNumbers +function PageLayout(props) { + return ; +} +``` +```` + + + +```jsx showLineNumbers +function PageLayout(props) { + return ; +} +``` + + + ## Syntax highlighting {#syntax-highlighting} Code blocks are text blocks wrapped around by strings of 3 backticks. You may check out [this reference](https://github.com/mdx-js/specification) for the specifications of MDX. @@ -590,7 +612,10 @@ export default function MyReactPage() { return (
{/* highlight-start */} - + {`function HelloCodeTitle(props) { return

Hello, {props.name}

; }`} @@ -602,15 +627,18 @@ export default function MyReactPage() { ``` - + {`function HelloCodeTitle(props) { return

Hello, {props.name}

; }`}
-The props accepted are `language` and `title`, in the same way as you write Markdown code blocks. +The props accepted are `language`, `title` and `showLineNumbers`, in the same way as you write Markdown code blocks. -Although discouraged, you can also pass in a `metastring` prop like `metastring='{1-2} title="/src/components/HelloCodeTitle.js"'`, which is how Markdown code blocks are handled under the hood. However, we recommend you [use comments for highlighting lines](#highlighting-with-comments). +Although discouraged, you can also pass in a `metastring` prop like `metastring='{1-2} title="/src/components/HelloCodeTitle.js" showLineNumbers'`, which is how Markdown code blocks are handled under the hood. However, we recommend you [use comments for highlighting lines](#highlighting-with-comments). As [previously stated](#using-jsx-markup), syntax highlighting is only applied when the children is a simple string.