feat(v2): add filename in CodeBlock (#2346)

* 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
This commit is contained in:
Kohhee Peace 2020-03-26 01:05:18 +08:00 committed by GitHub
parent 201c663318
commit 5e0d11dbaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 166 additions and 60 deletions

View file

@ -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 {
@ -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;
@ -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;
@ -90,16 +99,27 @@ export default ({children, className: languageClassName, metastring}) => {
code={children.replace(/\n$/, '')}
language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre className={classnames(className, styles.codeBlock)}>
<>
{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={styles.copyButton}
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 === '') {
@ -122,6 +142,8 @@ export default ({children, className: languageClassName, metastring}) => {
})}
</div>
</pre>
</div>
</>
)}
</Highlight>
);

View file

@ -5,6 +5,19 @@
* 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;
@ -12,6 +25,11 @@
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);
@ -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;
}

View file

@ -18,6 +18,7 @@ import Playground from '@theme/Playground';
import styles from './styles.module.css';
const highlightLinesRangeRegex = /{([\d,-]+)}/;
const codeBlockTitleRegex = /title=".*"/;
export default ({
children,
@ -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;
@ -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;
@ -109,16 +118,27 @@ export default ({
code={children.replace(/\n$/, '')}
language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre className={classnames(className, styles.codeBlock)}>
<>
{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={styles.copyButton}
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 === '') {
@ -141,6 +161,8 @@ export default ({
})}
</div>
</pre>
</div>
</>
)}
</Highlight>
);

View file

@ -5,6 +5,19 @@
* 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;
@ -12,6 +25,11 @@
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);
@ -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;
}

View file

@ -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))

View file

@ -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",