Skip to content

Commit

Permalink
feat(v2): add filename in CodeBlock (#2346)
Browse files Browse the repository at this point in the history
* feat: add filename in CodeBlock

* Fix code to use Regex to find title from markdown and Update style

* Fix reviewed point
- Delete unnecessary template literals
- Delete unnecessary "important!" from css

* Add title in live codeblock

* Just edit code order

* Add demo for code title

* Add docs about code title in markdown-features.mdx

* Make code title height scalable

* Rename codeBlockWrapper to codeBlockContent

* Make copyButton appear when hovering codeTitle

* Fix docs description about code title
  • Loading branch information
kohheepeace authored Mar 25, 2020
1 parent 201c663 commit 5e0d11d
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 66 deletions.
84 changes: 53 additions & 31 deletions packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import useThemeContext from '@theme/hooks/useThemeContext';
import styles from './styles.module.css';

const highlightLinesRangeRegex = /{([\d,-]+)}/;
const codeBlockTitleRegex = /title=".*"/;

export default ({children, className: languageClassName, metastring}) => {
const {
Expand All @@ -41,6 +42,7 @@ export default ({children, className: languageClassName, metastring}) => {
const target = useRef(null);
const button = useRef(null);
let highlightLines = [];
let codeBlockTitle = '';

const {isDarkTheme} = useThemeContext();
const lightModeTheme = prism.theme || defaultTheme;
Expand All @@ -52,6 +54,13 @@ export default ({children, className: languageClassName, metastring}) => {
highlightLines = rangeParser.parse(highlightLinesRange).filter(n => n > 0);
}

if (metastring && codeBlockTitleRegex.test(metastring)) {
codeBlockTitle = metastring
.match(codeBlockTitleRegex)[0]
.split('title=')[1]
.replace(/"+/g, '');
}

useEffect(() => {
let clipboard;

Expand Down Expand Up @@ -90,38 +99,51 @@ export default ({children, className: languageClassName, metastring}) => {
code={children.replace(/\n$/, '')}
language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre className={classnames(className, styles.codeBlock)}>
<button
ref={button}
type="button"
aria-label="Copy code to clipboard"
className={styles.copyButton}
onClick={handleCopyCode}>
{showCopied ? 'Copied' : 'Copy'}
</button>

<div ref={target} className={styles.codeBlockLines} style={style}>
{tokens.map((line, i) => {
if (line.length === 1 && line[0].content === '') {
line[0].content = '\n'; // eslint-disable-line no-param-reassign
}

const lineProps = getLineProps({line, key: i});

if (highlightLines.includes(i + 1)) {
lineProps.className = `${lineProps.className} docusaurus-highlight-code-line`;
}

return (
<div key={i} {...lineProps}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
);
})}
<>
{codeBlockTitle && (
<div style={style} className={styles.codeBlockTitle}>
{codeBlockTitle}
</div>
)}
<div className={styles.codeBlockContent}>
<button
ref={button}
type="button"
aria-label="Copy code to clipboard"
className={classnames(styles.copyButton, {
[styles.copyButtonWithTitle]: codeBlockTitle,
})}
onClick={handleCopyCode}>
{showCopied ? 'Copied' : 'Copy'}
</button>
<pre
className={classnames(className, styles.codeBlock, {
[styles.codeBlockWithTitle]: codeBlockTitle,
})}>
<div ref={target} className={styles.codeBlockLines} style={style}>
{tokens.map((line, i) => {
if (line.length === 1 && line[0].content === '') {
line[0].content = '\n'; // eslint-disable-line no-param-reassign
}

const lineProps = getLineProps({line, key: i});

if (highlightLines.includes(i + 1)) {
lineProps.className = `${lineProps.className} docusaurus-highlight-code-line`;
}

return (
<div key={i} {...lineProps}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
);
})}
</div>
</pre>
</div>
</pre>
</>
)}
</Highlight>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,31 @@
* LICENSE file in the root directory of this source tree.
*/

.codeBlockContent {
position: relative;
}

.codeBlockTitle {
border-top-left-radius: var(--ifm-pre-border-radius);
border-top-right-radius: var(--ifm-pre-border-radius);
font-weight: bold;
padding: 4px 12px;
border-bottom: 1px solid;
width: 100%;
}

.codeBlock {
overflow: auto;
display: block;
padding: 0;
margin: 0;
}

.codeBlockWithTitle {
border-top-left-radius: 0;
border-top-right-radius: 0;
}

.copyButton {
background: rgb(1, 22, 39);
border: 1px solid rgb(214, 222, 235);
Expand All @@ -30,7 +48,12 @@
bottom 200ms ease-in-out;
}

.codeBlock:hover > .copyButton {
.copyButtonWithTitle {
top: calc(var(--ifm-pre-padding));
}

.codeBlockTitle:hover + .codeBlockContent .copyButton,
.codeBlockContent:hover > .copyButton {
visibility: visible;
opacity: 1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Playground from '@theme/Playground';
import styles from './styles.module.css';

const highlightLinesRangeRegex = /{([\d,-]+)}/;
const codeBlockTitleRegex = /title=".*"/;

export default ({
children,
Expand Down Expand Up @@ -48,6 +49,7 @@ export default ({
const target = useRef(null);
const button = useRef(null);
let highlightLines = [];
let codeBlockTitle = '';

const {isDarkTheme} = useThemeContext();
const lightModeTheme = prism.theme || defaultTheme;
Expand All @@ -59,6 +61,13 @@ export default ({
highlightLines = rangeParser.parse(highlightLinesRange).filter(n => n > 0);
}

if (metastring && codeBlockTitleRegex.test(metastring)) {
codeBlockTitle = metastring
.match(codeBlockTitleRegex)[0]
.split('title=')[1]
.replace(/"+/g, '');
}

useEffect(() => {
let clipboard;

Expand Down Expand Up @@ -109,38 +118,51 @@ export default ({
code={children.replace(/\n$/, '')}
language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre className={classnames(className, styles.codeBlock)}>
<button
ref={button}
type="button"
aria-label="Copy code to clipboard"
className={styles.copyButton}
onClick={handleCopyCode}>
{showCopied ? 'Copied' : 'Copy'}
</button>

<div ref={target} className={styles.codeBlockLines} style={style}>
{tokens.map((line, i) => {
if (line.length === 1 && line[0].content === '') {
line[0].content = '\n'; // eslint-disable-line no-param-reassign
}

const lineProps = getLineProps({line, key: i});

if (highlightLines.includes(i + 1)) {
lineProps.className = `${lineProps.className} docusaurus-highlight-code-line`;
}

return (
<div key={i} {...lineProps}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
);
})}
<>
{codeBlockTitle && (
<div style={style} className={styles.codeBlockTitle}>
{codeBlockTitle}
</div>
)}
<div className={styles.codeBlockContent}>
<button
ref={button}
type="button"
aria-label="Copy code to clipboard"
className={classnames(styles.copyButton, {
[styles.copyButtonWithTitle]: codeBlockTitle,
})}
onClick={handleCopyCode}>
{showCopied ? 'Copied' : 'Copy'}
</button>
<pre
className={classnames(className, styles.codeBlock, {
[styles.codeBlockWithTitle]: codeBlockTitle,
})}>
<div ref={target} className={styles.codeBlockLines} style={style}>
{tokens.map((line, i) => {
if (line.length === 1 && line[0].content === '') {
line[0].content = '\n'; // eslint-disable-line no-param-reassign
}

const lineProps = getLineProps({line, key: i});

if (highlightLines.includes(i + 1)) {
lineProps.className = `${lineProps.className} docusaurus-highlight-code-line`;
}

return (
<div key={i} {...lineProps}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
);
})}
</div>
</pre>
</div>
</pre>
</>
)}
</Highlight>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,31 @@
* LICENSE file in the root directory of this source tree.
*/

.codeBlockContent {
position: relative;
}

.codeBlockTitle {
border-top-left-radius: var(--ifm-pre-border-radius);
border-top-right-radius: var(--ifm-pre-border-radius);
font-weight: bold;
padding: 4px 12px;
border-bottom: 1px solid;
width: 100%;
}

.codeBlock {
overflow: auto;
display: block;
padding: 0;
margin: 0;
}

.codeBlockWithTitle {
border-top-left-radius: 0;
border-top-right-radius: 0;
}

.copyButton {
background: rgb(1, 22, 39);
border: 1px solid rgb(214, 222, 235);
Expand All @@ -30,7 +48,12 @@
bottom 200ms ease-in-out;
}

.codeBlock:hover > .copyButton {
.copyButtonWithTitle {
top: calc(var(--ifm-pre-padding));
}

.codeBlockTitle:hover + .codeBlockContent .copyButton,
.codeBlockContent:hover > .copyButton {
visibility: visible;
opacity: 1;
}
Expand Down
17 changes: 17 additions & 0 deletions website/docs/markdown-features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,23 @@ function MyComponent(props) {
export default MyComponent;
```
### Code title
You can add title to code block by adding `title` key after the language (leave a space between them).
```jsx title="src/components/HelloCodeTitle.js"
function HelloCodeTitle(props) {
return <h1>Hello, {props.name}</h1>;
}
```
```jsx title="src/components/HelloCodeTitle.js"
function HelloCodeTitle(props) {
return <h1>Hello, {props.name}</h1>;
}
```
### Interactive code editor
(Powered by [React Live](https://github.com/FormidableLabs/react-live))
Expand Down
3 changes: 1 addition & 2 deletions website/docs/migrating-from-v1-to-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ This provides a clear distinction between Docusaurus' official packages and comm

Meanwhile, the default doc site functionalities provided by Docusaurus 1 are now provided by `@docusaurus/preset-classic`. Therefore, we need to add this dependency as well:

```json
// package.json
```json title="package.json"
{
dependencies: {
- "docusaurus": "^1.x.x",
Expand Down

0 comments on commit 5e0d11d

Please sign in to comment.