Skip to content

Commit

Permalink
feat(v2): Add playgroundPosition config for live codeblock (#4328)
Browse files Browse the repository at this point in the history
* docs(v2): Add configuration parameter to allow putting Result before Editor in @docusaurus/theme-live-codeblock

* update doc

* refactor as playgroundPosition

Co-authored-by: slorber <lorber.sebastien@gmail.com>
  • Loading branch information
tokarchyn and slorber authored Mar 5, 2021
1 parent f772c17 commit 98a4b3a
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 38 deletions.
1 change: 1 addition & 0 deletions packages/docusaurus-theme-live-codeblock/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@docusaurus/core": "2.0.0-alpha.70",
"@philpl/buble": "^0.19.7",
"clsx": "^1.1.1",
"joi": "^17.4.0",
"parse-numeric-range": "^1.2.0",
"prism-react-renderer": "^1.1.1",
"react-live": "^2.2.3"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

const {validateThemeConfig, DEFAULT_CONFIG} = require('../validateThemeConfig');

function testValidateThemeConfig(themeConfig) {
function validate(schema, cfg) {
const {value, error} = schema.validate(cfg, {
convert: false,
});
if (error) {
throw error;
}
return value;
}

return validateThemeConfig({validate, themeConfig});
}

describe('validateThemeConfig', () => {
test('undefined config', () => {
const liveCodeBlock = undefined;
expect(testValidateThemeConfig({liveCodeBlock})).toEqual({
liveCodeBlock: {
...DEFAULT_CONFIG,
},
});
});

test('unexist config', () => {
expect(testValidateThemeConfig({})).toEqual({
liveCodeBlock: {
...DEFAULT_CONFIG,
},
});
});

test('empty config', () => {
const liveCodeBlock = {};
expect(testValidateThemeConfig({liveCodeBlock})).toEqual({
liveCodeBlock: {
...DEFAULT_CONFIG,
},
});
});

test('playgroundPosition top', () => {
const liveCodeBlock = {
playgroundPosition: 'top',
};
expect(testValidateThemeConfig({liveCodeBlock})).toEqual({
liveCodeBlock: {
...DEFAULT_CONFIG,
...liveCodeBlock,
},
});
});

test('playgroundPosition bottom', () => {
const liveCodeBlock = {
playgroundPosition: 'bottom',
};
expect(testValidateThemeConfig({liveCodeBlock})).toEqual({
liveCodeBlock: {
...DEFAULT_CONFIG,
...liveCodeBlock,
},
});
});

test('playgroundPosition invalid string', () => {
const liveCodeBlock = {playgroundPosition: 'invalid'};
expect(() =>
testValidateThemeConfig({liveCodeBlock}),
).toThrowErrorMatchingInlineSnapshot(
`"\\"liveCodeBlock.playgroundPosition\\" must be one of [top, bottom]"`,
);
});
test('playgroundPosition invalid boolean', () => {
const liveCodeBlock = {playgroundPosition: true};
expect(() =>
testValidateThemeConfig({liveCodeBlock}),
).toThrowErrorMatchingInlineSnapshot(
`"\\"liveCodeBlock.playgroundPosition\\" must be one of [top, bottom]"`,
);
});
});
9 changes: 7 additions & 2 deletions packages/docusaurus-theme-live-codeblock/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
*/

const path = require('path');
const {validateThemeConfig} = require('./validateThemeConfig');

module.exports = function () {
function theme() {
return {
name: 'docusaurus-theme-live-codeblock',

Expand All @@ -25,4 +26,8 @@ module.exports = function () {
};
},
};
};
}

module.exports = theme;

theme.validateThemeConfig = validateThemeConfig;
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,56 @@ import clsx from 'clsx';
import Translate from '@docusaurus/Translate';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import usePrismTheme from '@theme/hooks/usePrismTheme';

import styles from './styles.module.css';

function Header({translateId, description, text}) {
return (
<div className={clsx(styles.playgroundHeader)}>
<Translate id={translateId} description={description}>
{text}
</Translate>
</div>
);
}

function ResultWithHeader() {
return (
<>
<Header
translateId="theme.Playground.result"
description="The result label of the live codeblocks"
text="Result"
/>
<div className={styles.playgroundPreview}>
<LivePreview />
<LiveError />
</div>
</>
);
}

function EditorWithHeader() {
return (
<>
<Header
translateId="theme.Playground.liveEditor"
description="The live editor label of the live codeblocks"
text="Live Editor"
/>
<LiveEditor className={styles.playgroundEditor} />
</>
);
}

export default function Playground({children, transformCode, ...props}) {
const {isClient} = useDocusaurusContext();
const {
isClient,
siteConfig: {
themeConfig: {
liveCodeBlock: {playgroundPosition},
},
},
} = useDocusaurusContext();
const prismTheme = usePrismTheme();

return (
Expand All @@ -26,33 +71,17 @@ export default function Playground({children, transformCode, ...props}) {
transformCode={transformCode || ((code) => `${code};`)}
theme={prismTheme}
{...props}>
<div
className={clsx(
styles.playgroundHeader,
styles.playgroundEditorHeader,
)}>
<Translate
id="theme.Playground.liveEditor"
description="The live editor label of the live codeblocks">
Live Editor
</Translate>
</div>
<LiveEditor className={styles.playgroundEditor} />
<div
className={clsx(
styles.playgroundHeader,
styles.playgroundPreviewHeader,
)}>
<Translate
id="theme.Playground.result"
description="The result label of the live codeblocks">
Result
</Translate>
</div>
<div className={styles.playgroundPreview}>
<LivePreview />
<LiveError />
</div>
{playgroundPosition === 'top' ? (
<>
<ResultWithHeader />
<EditorWithHeader />
</>
) : (
<>
<EditorWithHeader />
<ResultWithHeader />
</>
)}
</LiveProvider>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,18 @@
padding: 0.75rem;
text-transform: uppercase;
font-weight: bold;
background: var(--ifm-color-emphasis-200);
color: var(--ifm-color-content);
font-size: var(--ifm-code-font-size);
}

.playgroundEditorHeader {
.playgroundHeader:first-of-type {
background: var(--ifm-color-emphasis-600);
color: var(--ifm-color-content-inverse);
border-top-left-radius: var(--ifm-global-radius);
border-top-right-radius: var(--ifm-global-radius);
}

.playgroundPreviewHeader {
background: var(--ifm-color-emphasis-200);
color: var(--ifm-color-content);
}

.playgroundEditor {
font: var(--ifm-code-font-size) / var(--ifm-pre-line-height)
var(--ifm-font-family-monospace) !important;
Expand All @@ -38,7 +35,10 @@

.playgroundPreview {
border: 1px solid var(--ifm-color-emphasis-200);
padding: 1rem;
}

.playgroundPreview:last-of-type, .playgroundEditor:last-of-type {
border-bottom-left-radius: var(--ifm-global-radius);
border-bottom-right-radius: var(--ifm-global-radius);
padding: 1rem;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

const Joi = require('joi');

const DEFAULT_CONFIG = {
playgroundPosition: 'bottom',
};
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;

const Schema = Joi.object({
liveCodeBlock: Joi.object({
playgroundPosition: Joi.string()
.equal('top', 'bottom')
.default(DEFAULT_CONFIG.playgroundPosition),
})
.label('themeConfig.liveCodeBlock')
.default(DEFAULT_CONFIG),
});
exports.Schema = Schema;

exports.validateThemeConfig = function ({validate, themeConfig}) {
return validate(Schema, themeConfig);
};
17 changes: 17 additions & 0 deletions website/docs/api/themes/theme-live-codeblock.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,20 @@ This theme provides a `@theme/CodeBlock` component that is powered by react-live
```bash npm2yarn
npm install --save @docusaurus/theme-live-codeblock
```

### Configuration

```jsx title="docusaurus.config.js"
module.exports = {
plugins: ['@docusaurus/theme-live-codeblock'],
themeConfig: {
liveCodeBlock: {
/**
* The position of the live playground, above or under the editor
* Possible values: "top" | "bottom"
*/
playgroundPosition: 'bottom',
},
},
};
```
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ function Clock(props) {
}
```

### Imports

:::caution react-live and imports

It is not possible to import components directly from the react-live code editor, you have to define available imports upfront.
Expand Down
3 changes: 3 additions & 0 deletions website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ const LocaleConfigs = isI18nStaging
],
],
themeConfig: {
liveCodeBlock: {
playgroundPosition: 'bottom',
},
hideableSidebar: true,
colorMode: {
defaultMode: 'light',
Expand Down

0 comments on commit 98a4b3a

Please sign in to comment.