Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a69e1e6

Browse files
committedApr 23, 2018
first
0 parents  commit a69e1e6

File tree

10 files changed

+4590
-0
lines changed

10 files changed

+4590
-0
lines changed
 

‎.babelrc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"env": {
3+
"production": {
4+
"presets": [
5+
[
6+
"env",
7+
{
8+
"targets": {
9+
"browsers": ["last 4 versions", "safari >= 7", "ie >= 9"],
10+
"uglify": true
11+
}
12+
}
13+
],
14+
"react"
15+
]
16+
}
17+
}
18+
}

‎.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.DS_Store
2+
.vscode
3+
node_modules
4+
5+
yarn-error.log
6+
7+
/index.js

‎.npmignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.vsdode
2+
3+
node_modules
4+
src
5+
6+
.babelrc
7+
.prettierrc
8+
9+
yarn.lock

‎.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"trailingComma": "es5",
3+
"singleQuote": true
4+
}

‎README.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# gatsby-remark-embedded-codesandbox
2+
3+
This plugin adds support for generting embedded [Codesandbox](https://codesandbox.io/), specifying a folder in local files to populate the contents of it.
4+
This enables example code to be stored along side of, and revisioned with, your website content.
5+
6+
This plugin is based on [gatsby-remark-code-repls](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-remark-code-repls).
7+
8+
## Getting started
9+
10+
To embed a Codesandbox editor in you markdown/remark content, simply add a link with the custom protocol pointing to the folder desired folder:
11+
12+
```md
13+
[embedded example](embedded-codesandbox://example/folder)
14+
```
15+
16+
It will scan the folder and generate the proper html to include the editor.
17+
18+
## Overview
19+
20+
For example, given the following project directory structure:
21+
22+
```
23+
examples/
24+
├── hello-world-example
25+
│   ├── package.json
26+
│   ├── index.html
27+
│   └── index.js
28+
├── some-other-example
29+
│   ├── package.json
30+
│   └── index.js
31+
```
32+
33+
These example files can be referenced via links in markdown that get transformed
34+
to embedded editors. For example:
35+
36+
```md
37+
<!-- before -->
38+
39+
[hello world example](embedded-codesandbox://hello-world-example)
40+
41+
<!-- after -->
42+
43+
<iframe src="https://codesandbox.io/api/v1/sandboxes/define?embed=1&parameters=N4IgZglgNgpgziAXKADgQwMYGs0HMYB0AVnAPYB2SoGFALjObVSOWgLYxIgwAe7KsEAF8hAGhARyAE14EAFrTZRmNRgyaIQAHgVKAfFoBGpKQE8DAemNnLuqHuHjJMnsQTIQq-oy6q4tAAIwUlIAgF4AgB0QQzQAJ2iAbmERIA&query=hidenavigation%3D1%26view%3Dpreview" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;\\" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
44+
```
45+
46+
> NB: Codesandbox [**requires** a `package.json` file](https://codesandbox.io/docs/importing#how-it-works) in order to work!
47+
> You can define dependencies such as `react` that will be included in the sandbox.
48+
> If you don't need any just add the minimum required:
49+
>
50+
> ```json
51+
> {
52+
> "name": "example",
53+
> "dependencies": {}
54+
> }
55+
> ```
56+
57+
### How does it work?
58+
59+
CodeSandbox uses the [same URL compression schema used by the Babel REPL](https://github.com/babel/website/blob/c9dd1f516985f7267eb58c286789e0c66bc0a21d/js/repl/UriUtils.js#L22-L26) to embed the local code example in a URL.
60+
61+
This is than passed to the (awesome) [define api](https://codesandbox.io/docs/importing#define-api) to generate a sandbox on the fly.
62+
63+
## Installation
64+
65+
`yarn add gatsby-remark-embedded-codesandbox`
66+
67+
## Usage
68+
69+
```javascript
70+
// In your gatsby-config.js
71+
{
72+
resolve: 'gatsby-transformer-remark',
73+
options: {
74+
plugins: [
75+
{
76+
resolve: 'gastby-remark-embedded-codesandbox',
77+
options: {
78+
// Required:
79+
80+
// Example code folders are relative to this dir.
81+
// eg src/_examples/some-example-folder
82+
directory: `${__dirname}/src/_examples/`,
83+
84+
// Optional:
85+
86+
// Custom protocol for parsing the embedding link
87+
// default:
88+
protocol: 'embedded-codesandbox://',
89+
90+
// Customise Codesandbox embedding options:
91+
// https://codesandbox.io/docs/embedding#embed-options
92+
// default:
93+
embedOptions: {
94+
view: 'preview',
95+
hidenavigation: 1,
96+
},
97+
98+
// Customise the embedding iframe given the generated url
99+
// default:
100+
getIframe: url => `<iframe src="${url}" class="embedded-codesandbox" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>`
101+
}
102+
}
103+
]
104+
}
105+
}
106+
```

‎package.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "gatsby-remark-embedded-codesandbox",
3+
"version": "1.0.0",
4+
"description": "Gatsby Remark plugin for embedding Codesandbox given a folder of files",
5+
"main": "index.js",
6+
"repository": "https://github.com/elboman/gatsby-remark-embedded-codesandbox",
7+
"author": "Marco Botto <marco.botto@gmail.com>",
8+
"bugs": {
9+
"url": "https://github.com/elboman/gatsby-remark-embedded-codesandbox/issues"
10+
},
11+
"keywords": [
12+
"gatsby",
13+
"gatsby-plugin",
14+
"remark",
15+
"codesandbox",
16+
"embed",
17+
"embedded"
18+
],
19+
"license": "MIT",
20+
"private": false,
21+
"dependencies": {
22+
"jest": "^22.4.3",
23+
"lz-string": "^1.4.4",
24+
"query-string": "^6.0.0",
25+
"unist-util-map": "^1.0.3"
26+
},
27+
"devDependencies": {
28+
"babel-cli": "^6.26.0",
29+
"babel-preset-env": "^1.6.1",
30+
"babel-preset-react": "^6.24.1",
31+
"cross-env": "^5.1.4",
32+
"prettier": "^1.12.1",
33+
"remark": "^9.0.0"
34+
},
35+
"scripts": {
36+
"test": "jest",
37+
"build": "babel src --out-dir . --ignore __tests__",
38+
"prepublish": "cross-env NODE_ENV=production yarn build"
39+
}
40+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`gatsby-remark-embedded-codesandbox generates an embedded sandbox for a nested example folder 1`] = `
4+
Object {
5+
"type": "html",
6+
"value": "<iframe src=\\"https://codesandbox.io/api/v1/sandboxes/define?embed=1&parameters=N4IgZglgNgpgziAXKADgQwMYGs0HMYB0AVnAPYB2SoGFALjObVSOWgLYxIgwAe7KsEAF8hAGhARyAE14EAFrTZRmNRgyaIQAHgVKAfFoBGpKQE8DAemNnLuqHuHjJMnsQTIQq-oy6q4tAAIwUlIAgF4AgB0QQzQAJ2iAbmERIA&query=hidenavigation%3D1%26view%3Dpreview\\" class=\\"embedded-codesandbox\\" sandbox=\\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\\"></iframe>",
7+
}
8+
`;
9+
10+
exports[`gatsby-remark-embedded-codesandbox generates an embedded sandbox for the specified example folder 1`] = `
11+
Object {
12+
"type": "html",
13+
"value": "<iframe src=\\"https://codesandbox.io/api/v1/sandboxes/define?embed=1&parameters=N4IgZglgNgpgziAXKADgQwMYGs0HMYB0AVnAPYB2SoGFALjObVSOWgLYxIgwAe7KsEAF8hAGhARyAE14EAFrTZRmNRgyaIQAHgVKAfFoBGpKQE8DAemNnLuqHuHjJMnsQTIQq-oy6q4tAAIwUlIAgF4AgB0QQzQAJ2iAbmERIA&query=hidenavigation%3D1%26view%3Dpreview\\" class=\\"embedded-codesandbox\\" sandbox=\\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\\"></iframe>",
14+
}
15+
`;
16+
17+
exports[`gatsby-remark-embedded-codesandbox generates an embedded sandbox using a custom getIframe function 1`] = `
18+
Object {
19+
"type": "html",
20+
"value": "<iframe src=\\"https://codesandbox.io/api/v1/sandboxes/define?embed=1&parameters=N4IgZglgNgpgziAXKADgQwMYGs0HMYB0AVnAPYB2SoGFALjObVSOWgLYxIgwAe7KsEAF8hAGhARyAE14EAFrTZRmNRgyaIQAHgVKAfFoBGpKQE8DAemNnLuqHuHjJMnsQTIQq-oy6q4tAAIwUlIAgF4AgB0QQzQAJ2iAbmERIA&query=hidenavigation%3D1%26view%3Dpreview\\" />",
21+
}
22+
`;
23+
24+
exports[`gatsby-remark-embedded-codesandbox generates an embedded sandbox using a custom protocol 1`] = `
25+
Object {
26+
"type": "html",
27+
"value": "<iframe src=\\"https://codesandbox.io/api/v1/sandboxes/define?embed=1&parameters=N4IgZglgNgpgziAXKADgQwMYGs0HMYB0AVnAPYB2SoGFALjObVSOWgLYxIgwAe7KsEAF8hAGhARyAE14EAFrTZRmNRgyaIQAHgVKAfFoBGpKQE8DAemNnLuqHuHjJMnsQTIQq-oy6q4tAAIwUlIAgF4AgB0QQzQAJ2iAbmERIA&query=hidenavigation%3D1%26view%3Dpreview\\" class=\\"embedded-codesandbox\\" sandbox=\\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\\"></iframe>",
28+
}
29+
`;

‎src/__tests__/index.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
jest.mock(`fs`, () => {
2+
return {
3+
existsSync: jest.fn(),
4+
readdirSync: jest.fn(),
5+
readFileSync: jest.fn(),
6+
};
7+
});
8+
9+
const fs = require(`fs`);
10+
const Remark = require(`remark`);
11+
const plugin = require(`../index`);
12+
13+
const remark = new Remark();
14+
15+
const getNodeContent = node => node.children[0].children[0];
16+
17+
describe('gatsby-remark-embedded-codesandbox', () => {
18+
beforeEach(() => {
19+
fs.existsSync.mockReset();
20+
fs.readdirSync.mockReset();
21+
fs.readFileSync.mockReset();
22+
23+
fs.existsSync.mockReturnValue(true);
24+
fs.readdirSync.mockReturnValue(['package.json', 'index.html', 'index.js']);
25+
fs.readFileSync
26+
.mockReturnValueOnce('{ "name": "example" }')
27+
.mockReturnValueOnce('<html><body></body></html>')
28+
.mockReturnValueOnce('const foo = "bar";');
29+
});
30+
31+
it(`generates an embedded sandbox for the specified example folder`, async () => {
32+
const markdownAST = remark.parse(`[](embedded-codesandbox://example)`);
33+
const transformed = plugin({ markdownAST }, { directory: `examples` });
34+
expect(getNodeContent(transformed)).toMatchSnapshot();
35+
});
36+
37+
it(`generates an embedded sandbox for a nested example folder`, async () => {
38+
const markdownAST = remark.parse(
39+
`[](embedded-codesandbox://path/to/folder)`
40+
);
41+
const transformed = plugin({ markdownAST }, { directory: `examples` });
42+
expect(fs.readdirSync).toHaveBeenCalledWith('examples/path/to/folder');
43+
expect(getNodeContent(transformed)).toMatchSnapshot();
44+
});
45+
46+
it('generates an embedded sandbox using a custom protocol', async () => {
47+
const markdownAST = remark.parse(`[](custom-embedded-protocol://example)`);
48+
const transformed = plugin(
49+
{ markdownAST },
50+
{ directory: 'examples', protocol: 'custom-embedded-protocol://' }
51+
);
52+
expect(getNodeContent(transformed)).toMatchSnapshot();
53+
});
54+
55+
it('generates an embedded sandbox using custom embedding options', async () => {
56+
const markdownAST = remark.parse(`[](embedded-codesandbox://example)`);
57+
const transformed = plugin(
58+
{ markdownAST },
59+
{
60+
directory: 'examples',
61+
embedOptions: {
62+
view: 'split',
63+
hidenavigation: 0,
64+
},
65+
}
66+
);
67+
expect(getNodeContent(transformed).value).toEqual(
68+
expect.stringContaining('query=hidenavigation%3D0%26view%3Dsplit')
69+
);
70+
});
71+
72+
it('generates an embedded sandbox using a custom getIframe function', async () => {
73+
const markdownAST = remark.parse(`[](embedded-codesandbox://example)`);
74+
const transformed = plugin(
75+
{ markdownAST },
76+
{
77+
directory: 'examples',
78+
getIframe: url => `<iframe src="${url}" />`,
79+
}
80+
);
81+
expect(getNodeContent(transformed)).toMatchSnapshot();
82+
});
83+
});
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.