mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-16 10:37:20 +02:00
feat: code block tab (#1063)
* Try to find a way to recognize the codeblock tabs, its title, and where it ends - I try using DOCUSAURUS_CODE_TABS to mark the start - Use TAB_TITLE to mark the title of the tab - END_TAB to mark the end of that tab - END_DOCUSAURUS_CODE_TABS to mark the end of the whole code blocks then parse using regex and render accordingly * Added on click hook * Added example on how to write it, how to use it, how it will look like can be reverted later * Fix css error * - Move addEventListener part to lib/static - Remove comments * Add documentation * Remove examples * Change syntax of the codetabs
This commit is contained in:
parent
4ce7ae2c98
commit
5ce85e5b5e
6 changed files with 207 additions and 3 deletions
|
@ -132,6 +132,42 @@ will lead to a table of contents of the functions:
|
|||
|
||||
and each function will link to their corresponding sections in the page.
|
||||
|
||||
|
||||
### Code tabs
|
||||
|
||||
Docusaurus provides code tabs by default. To use code tabs, first, mark the start and end of a code tabs group, by using `<!--DOCUSAURUS_CODE_TABS-->` and `<!--END_DOCUSAURUS_CODE_TABS-->` respectively.
|
||||
Secondly, start each tab with `<!--[TAB_TITLE]-->`.
|
||||
|
||||
Example:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Javascript-->
|
||||
```js
|
||||
console.log("Hello, world!");
|
||||
```
|
||||
<!--Python-->
|
||||
```py
|
||||
print("Hello, world!")
|
||||
```
|
||||
<!--C-->
|
||||
```C
|
||||
#include
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Hello, world!");
|
||||
}
|
||||
```
|
||||
<!--Pascal-->
|
||||
```Pascal
|
||||
program HelloWorld;
|
||||
begin
|
||||
WriteLn('Hello, world!');
|
||||
end.
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
|
||||
## Syntax Highlighting
|
||||
|
||||
Syntax highlighting is enabled by default on fenced code blocks. The language should be detected automatically, but you can sometimes get better results by specifying the language. You can do so using an [info string](https://github.github.com/gfm/#example-111), following the three opening backticks. The following JavaScript example...
|
||||
|
|
50
v1/lib/core/CodeTabsMarkdownBlock.js
Normal file
50
v1/lib/core/CodeTabsMarkdownBlock.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
const React = require('react');
|
||||
const Remarkable = require('./Remarkable');
|
||||
|
||||
/**
|
||||
* The MarkdownBlock component is used to parse markdown and render to HTML.
|
||||
*/
|
||||
class MarkdownBlock extends React.Component {
|
||||
render() {
|
||||
const groupId = _.uniqueId();
|
||||
|
||||
const tabs = this.props.children.map(({title, content}) => ({
|
||||
id: _.uniqueId(),
|
||||
groupId,
|
||||
label: title,
|
||||
lang: title,
|
||||
panelContent: <Remarkable source={content} />,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="tabs">
|
||||
<div className="nav-tabs">
|
||||
{tabs.map((t, i) => (
|
||||
<div
|
||||
className={`nav-link${i === 0 ? ' active' : ''}`}
|
||||
id={`${t.id}-tab`}
|
||||
data-group={`group_${t.groupId}`}
|
||||
data-tab={`tabpanel_${t.id}`}>
|
||||
{t.label}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="tab-content">
|
||||
{tabs.map((t, i) => (
|
||||
<div
|
||||
className={`tab-pane${i === 0 ? ' active' : ''}`}
|
||||
data-group={`group_${t.groupId}`}
|
||||
tabIndex="-1"
|
||||
id={`tabpanel_${t.id}`}>
|
||||
{t.panelContent}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MarkdownBlock;
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
const React = require('react');
|
||||
const MarkdownBlock = require('./MarkdownBlock.js');
|
||||
const CodeTabsMarkdownBlock = require('./CodeTabsMarkdownBlock.js');
|
||||
|
||||
const translate = require('../server/translate.js').translate;
|
||||
|
||||
|
@ -17,8 +18,48 @@ const translateThisDoc = translate(
|
|||
'Translate this Doc|recruitment message asking to translate the docs',
|
||||
);
|
||||
|
||||
const splitTabsToTitleAndContent = content => {
|
||||
const titles = content.match(/<!--(.*?)-->/gms);
|
||||
const tabs = content.split(/<!--.*?-->/gms);
|
||||
if (!titles || !tabs || !titles.length || !tabs.length) return [];
|
||||
tabs.shift();
|
||||
const result = titles.map((title, idx) => ({
|
||||
title: title.substring(4, title.length - 3),
|
||||
content: tabs[idx],
|
||||
}));
|
||||
return result;
|
||||
};
|
||||
|
||||
// inner doc component for article itself
|
||||
class Doc extends React.Component {
|
||||
renderContent() {
|
||||
const {content} = this.props;
|
||||
let inCodeTabs = false;
|
||||
const contents = content.split(
|
||||
/(<!--DOCUSAURUS_CODE_TABS-->\n)(.*?)(\n<!--END_DOCUSAURUS_CODE_TABS-->)/gms,
|
||||
);
|
||||
|
||||
const renderResult = contents.map(c => {
|
||||
if (c === '<!--DOCUSAURUS_CODE_TABS-->\n') {
|
||||
inCodeTabs = true;
|
||||
return null;
|
||||
}
|
||||
if (c === '\n<!--END_DOCUSAURUS_CODE_TABS-->') {
|
||||
inCodeTabs = false;
|
||||
return null;
|
||||
}
|
||||
if (inCodeTabs) {
|
||||
return (
|
||||
<CodeTabsMarkdownBlock>
|
||||
{splitTabsToTitleAndContent(c)}
|
||||
</CodeTabsMarkdownBlock>
|
||||
);
|
||||
}
|
||||
return <MarkdownBlock>{c}</MarkdownBlock>;
|
||||
});
|
||||
return renderResult;
|
||||
}
|
||||
|
||||
render() {
|
||||
let docSource = this.props.source;
|
||||
|
||||
|
@ -67,9 +108,7 @@ class Doc extends React.Component {
|
|||
<h1 className="postHeaderTitle">{this.props.title}</h1>
|
||||
)}
|
||||
</header>
|
||||
<article>
|
||||
<MarkdownBlock>{this.props.content}</MarkdownBlock>
|
||||
</article>
|
||||
<article>{this.renderContent()}</article>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -188,6 +188,7 @@ class Head extends React.Component {
|
|||
rel="stylesheet"
|
||||
href={`${this.props.config.baseUrl}css/main.css`}
|
||||
/>
|
||||
<script src={`${this.props.config.baseUrl}js/codetabs.js`} />
|
||||
</head>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2361,3 +2361,57 @@ input::placeholder {
|
|||
padding: 5px 0;
|
||||
}
|
||||
/* End of Footer */
|
||||
|
||||
|
||||
.tabs {
|
||||
border-top: 1px solid #cfcfcf;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
display: flex;
|
||||
border-bottom: 4px solid #e0e0e0;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.nav-tabs::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabs .tab-pane:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tabs .nav-tabs > div {
|
||||
font-size: 14px;
|
||||
line-height: 1.14286;
|
||||
padding: 12px 16px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tabs .nav-tabs > div.active {
|
||||
border-bottom: 4px solid $primaryColor;
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-pane.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tab-pane > pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.tab-pane > pre > code {
|
||||
margin-top: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
|
24
v1/lib/static/js/codetabs.js
Normal file
24
v1/lib/static/js/codetabs.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Turn off ESLint for this file because it's sent down to users as-is.
|
||||
/* eslint-disable */
|
||||
window.addEventListener('load', function() {
|
||||
// add event listener for all tab
|
||||
document.querySelectorAll('.nav-link').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
const groupId = e.target.getAttribute('data-group');
|
||||
document
|
||||
.querySelectorAll(`.nav-link[data-group=${groupId}]`)
|
||||
.forEach(function(el) {
|
||||
el.classList.remove('active');
|
||||
});
|
||||
document
|
||||
.querySelectorAll(`.tab-pane[data-group=${groupId}]`)
|
||||
.forEach(function(el) {
|
||||
el.classList.remove('active');
|
||||
});
|
||||
e.target.classList.add('active');
|
||||
document
|
||||
.querySelector(`#${e.target.getAttribute('data-tab')}`)
|
||||
.classList.add('active');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue