mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-14 00:32:47 +02:00
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:
parent
201c663318
commit
5e0d11dbaf
6 changed files with 166 additions and 60 deletions
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue