Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #130 from readmeio/enhancement/copy-code-button
Browse files Browse the repository at this point in the history
Add a button to copy code samples
  • Loading branch information
mjcuva authored Aug 9, 2018
2 parents 8a6aa08 + 3fac3d7 commit dc05e7c
Show file tree
Hide file tree
Showing 9 changed files with 9,528 additions and 982 deletions.
8,160 changes: 7,801 additions & 359 deletions example/bundle-hub2.css

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions packages/api-explorer/__tests__/lib/generate-code-snippet.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ const operation = {
const values = { path: { id: 123 } };

test('should generate a HTML snippet for each lang', () => {
const snippet = generateCodeSnippet(oas, operation, {}, 'node');
const { snippet } = generateCodeSnippet(oas, operation, {}, 'node');

expect(typeof snippet).toBe('string');
expect(snippet).toEqual(expect.stringMatching(/cm-s-tomorrow-night/));
});

test('should pass through values to code snippet', () => {
const snippet = generateCodeSnippet(oas, operation, values, 'node');
const { snippet } = generateCodeSnippet(oas, operation, values, 'node');

expect(snippet).toEqual(expect.stringMatching('http://example.com/path/123'));
});

test('should not contain proxy url', () => {
const snippet = generateCodeSnippet(
const { snippet } = generateCodeSnippet(
Object.assign({}, oas, { [extensions.PROXY_ENABLED]: true }),
operation,
values,
Expand All @@ -46,11 +46,17 @@ test('should not contain proxy url', () => {
});

test('javascript should not contain `withCredentials`', () => {
const snippet = generateCodeSnippet(oas, operation, {}, 'javascript');
const { snippet } = generateCodeSnippet(oas, operation, {}, 'javascript');

expect(snippet).not.toMatch(/withCredentials/);
});

test('should return with unhighlighted code', () => {
const { code } = generateCodeSnippet(oas, operation, {}, 'javascript');

expect(code).not.toMatch(/cm-s-tomorrow-night/);
});

describe('#getLangName()', () => {
it('should convert name to correct case', () => {
expect(getLangName('go')).toBe('Go');
Expand Down
2 changes: 1 addition & 1 deletion packages/api-explorer/dist/index.js

Large diffs are not rendered by default.

2,242 changes: 1,645 additions & 597 deletions packages/api-explorer/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/api-explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"marked": "github:readmeio/marked",
"prop-types": "^15.5.10",
"react": "^16.2.0",
"react-copy-to-clipboard": "^5.0.1",
"react-jsonschema-form": "github:domharrington/react-jsonschema-form#dist-committed",
"react-waypoint": "^7.3.1",
"whatwg-fetch": "^2.0.3"
Expand Down Expand Up @@ -71,7 +72,6 @@
"eslint-plugin-react": "^7.1.0",
"jest": "^22.0.4",
"jsinspect": "^0.12.6",
"mocha": "^3.4.2",
"node-fetch": "^2.0.0-alpha.9",
"nyc": "^11.0.3",
"prettier": "^1.6.1",
Expand Down
26 changes: 16 additions & 10 deletions packages/api-explorer/src/CodeSample.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const Oas = require('./lib/Oas');

const { Operation } = Oas;

const CopyCode = require('./CopyCode');

const syntaxHighlighter = require('@readme/syntax-highlighter');

const generateCodeSnippet = require('./lib/generate-code-snippet');
Expand Down Expand Up @@ -36,15 +38,18 @@ class CodeSample extends React.Component {
<div className="code-sample-body">
{examplesWithLanguages.map(example => {
return (
<pre
className="tomorrow-night tabber-body"
style={{ display: this.props.language === example.language ? 'block' : '' }}
key={example.language} // eslint-disable-line react/no-array-index-key
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: syntaxHighlighter(example.code || '', example.language, true),
}}
/>
<div style={{ display: this.props.language === example.language ? 'block' : 'none' }}>
<CopyCode key={`copy-${example.language}`} code={example.code} />
<pre
className="tomorrow-night tabber-body"
key={example.language} // eslint-disable-line react/no-array-index-key
// eslint-disable-next-line react/no-danger
style={{ display: this.props.language === example.language ? 'block' : '' }}
dangerouslySetInnerHTML={{
__html: syntaxHighlighter(example.code || '', example.language, true),
}}
/>
</div>
);
})}
</div>
Expand All @@ -62,7 +67,7 @@ class CodeSample extends React.Component {
return <div className="hub-no-code">No code samples available</div>;
}
if (examples.length) return this.renderExamples(examples, setLanguage);
const snippet = generateCodeSnippet(oas, operation, formData, language);
const { snippet, code } = generateCodeSnippet(oas, operation, formData, language);
return (
<div>
<ul className="code-sample-tabs">
Expand All @@ -86,6 +91,7 @@ class CodeSample extends React.Component {
))}
</ul>
<div className="hub-code-auto">
<CopyCode code={code} />
<pre
className={`tomorrow-night hub-lang hub-lang-${language}`}
// eslint-disable-next-line react/no-danger
Expand Down
38 changes: 38 additions & 0 deletions packages/api-explorer/src/CopyCode.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const React = require('react');
const PropTypes = require('prop-types');
const { CopyToClipboard } = require('react-copy-to-clipboard');

class CopyCode extends React.Component {
constructor(props) {
super(props);

this.state = {
copied: false,
};

this.onCopy = this.onCopy.bind(this);
}

onCopy() {
this.setState({ copied: true });
setTimeout(() => {
this.setState({ copied: false });
}, 1000);
}

render() {
return (
<CopyToClipboard text={this.props.code} onCopy={this.onCopy}>
<button className="copy-code-button main_background">
{this.state.copied ? <span>Copied</span> : <span>Copy</span>}
</button>
</CopyToClipboard>
);
}
}

module.exports = CopyCode;

CopyCode.propTypes = {
code: PropTypes.string.isRequired,
};
22 changes: 13 additions & 9 deletions packages/api-explorer/src/block-types/Code.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const syntaxHighlighter = require('@readme/syntax-highlighter');
const statusCodes = require('../lib/statuscodes');
const CopyCode = require('../CopyCode');
const PropTypes = require('prop-types');
const React = require('react');
const classNames = require('classnames');
Expand Down Expand Up @@ -58,17 +59,20 @@ class BlockCode extends React.Component {

<div className="block-code-code">
{codes.map((code, i) => (
// eslint-disable-next-line react/no-array-index-key
<pre key={i} style={{ display: i === this.state.activeTab ? 'block' : 'none' }}>
<React.Fragment>
<CopyCode code={code.code} />
{
<code
// eslint-disable-next-line
dangerouslySetInnerHTML={{
__html: syntaxHighlighter(code.code, code.language, dark),
}}
/>
// eslint-disable-next-line react/no-array-index-key
<pre key={i} style={{ display: i === this.state.activeTab ? 'block' : 'none' }}>
<code
// eslint-disable-next-line
dangerouslySetInnerHTML={{
__html: syntaxHighlighter(code.code, code.language, dark),
}}
/>
</pre>
}
</pre>
</React.Fragment>
))}
</div>
</div>
Expand Down
4 changes: 3 additions & 1 deletion packages/api-explorer/src/lib/generate-code-snippet.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ module.exports = (oas, operation, values, lang) => {
return undefined;
}

return syntaxHighlighter(snippet.convert(...language.httpsnippet), language.highlight, true);
const code = snippet.convert(...language.httpsnippet);

return { snippet: syntaxHighlighter(code, language.highlight, true), code };
};

module.exports.getLangName = lang =>
Expand Down

0 comments on commit dc05e7c

Please sign in to comment.