Skip to content

Commit d0ff8cc

Browse files
authored
Merge pull request #345 from primer/stories-from-markdown
Stories from markdown
2 parents 5bb31cd + aab31b5 commit d0ff8cc

File tree

6 files changed

+74
-16
lines changed

6 files changed

+74
-16
lines changed

.storybook/config.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { configure } from '@storybook/react'
1+
import React from 'react'
2+
import { configure, addDecorator } from '@storybook/react'
23
import { setOptions } from '@storybook/addon-options'
34
import '../modules/primer-css/index.scss'
45

@@ -8,6 +9,12 @@ setOptions({
89
showDownPanel: false,
910
})
1011

12+
addDecorator(story => (
13+
<div className='p-4'>
14+
{story()}
15+
</div>
16+
))
17+
1118
const contexts = [
1219
require.context('.', true, /\.js$/),
1320
require.context('../modules', true, /stories.*\.js$/),
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import remark from 'remark'
2+
import parents from 'unist-util-parents'
3+
import select from 'unist-util-select'
4+
import findBefore from 'unist-util-find-before'
5+
import htmlToReact from 'html-to-react'
6+
import parsePairs from 'parse-pairs'
7+
8+
const htmlParser = new htmlToReact.Parser()
9+
10+
const nodeToStory = (node, file) => {
11+
const html = node.value
12+
const element = htmlParser.parse(html)
13+
const pairs = node.lang.replace(/^html\s*/, '')
14+
const attrs = pairs.length ? parsePairs(pairs) : {}
15+
const title = attrs.title || getPreviousHeading(node) ||
16+
`story @ ${file}:${node.position.start.line}`
17+
return {
18+
title,
19+
story: () => element,
20+
attrs,
21+
html,
22+
file,
23+
node,
24+
}
25+
}
26+
27+
const getPreviousHeading = node => {
28+
const heading = findBefore(node.parent, node, 'heading')
29+
return (heading && !heading.used)
30+
? (heading.used = true, heading.children.map(c => c.value).join(''))
31+
: undefined
32+
}
33+
34+
export default req => {
35+
return req.keys().reduce((stories, file) => {
36+
const content = req(file)
37+
const ast = parents(remark.parse(content))
38+
const path = file.replace(/^\.\//, '')
39+
return stories.concat(
40+
select(ast, 'code[lang^=html]')
41+
.map(node => nodeToStory(node, path))
42+
.filter(({attrs}) => attrs.story !== "false")
43+
)
44+
}, [])
45+
}

.storybook/webpack.config.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ const modulesPath = path.resolve(__dirname, "../modules")
55
module.exports = {
66
module: {
77
rules: [
8+
{
9+
test: /\.md$/,
10+
use: "raw-loader",
11+
},
812
{
913
test: /\.scss$/,
1014
loaders: [
@@ -28,7 +32,7 @@ module.exports = {
2832
},
2933
],
3034
include: modulesPath,
31-
}
32-
]
35+
},
36+
],
3337
},
3438
}

modules/primer-breadcrumb/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Breadcrumbs are used to show taxonomical context on pages that are many levels d
2222

2323
#### Usage
2424

25-
```html
25+
```html title="Breadcrumb"
2626
<nav aria-label="Breadcrumb">
2727
<ol>
2828
<li class="breadcrumb-item text-small"><a href="/business">Business</a></li>
Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import React from 'react'
22
import { storiesOf } from '@storybook/react'
3+
import storiesFromMarkdown from '../../.storybook/lib/storiesFromMarkdown'
34

4-
storiesOf('Breadcrumb', module)
5-
.add('breadcrumb', () => (
6-
<div className='p-4'>
7-
<nav aria-label='Breadcrumb'>
8-
<ol>
9-
<li className='breadcrumb-item text-small'><a href='/business'>Business</a></li>
10-
<li className='breadcrumb-item text-small'><a href='/business/customers'>Customers</a></li>
11-
<li className='breadcrumb-item breadcrumb-item-selected text-small text-gray' aria-current='page'>MailChimp</li>
12-
</ol>
13-
</nav>
14-
</div>
15-
))
5+
const stories = storiesOf('Breadcrumb', module)
6+
7+
storiesFromMarkdown(require.context('.', true, /\.md$/))
8+
.forEach(({title, story}) => {
9+
stories.add(title, story)
10+
})

package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,27 @@
2424
"commit-status": "^4.1.0",
2525
"css-loader": "^0.28.4",
2626
"glob": "^7.1.2",
27+
"html-to-react": "^1.2.11",
2728
"lerna": "^2.0.0",
2829
"node-sass": "^4.5.3",
2930
"npm-run-all": "^4.0.2",
3031
"octicons": "^6.0.1",
32+
"parse-pairs": "^0.2.2",
3133
"postcss-loader": "^2.0.6",
3234
"primer-module-build": "^1.0.2",
35+
"raw-loader": "^0.5.1",
3336
"react": "^15.6.1",
3437
"react-dom": "^15.6.1",
3538
"react-svg-inline": "^2.0.0",
39+
"remark": "^8.0.0",
3640
"sass-loader": "^6.0.6",
3741
"semver": "^5.3.0",
3842
"style-loader": "^0.18.2",
3943
"stylelint": "^7.13.0",
4044
"stylelint-config-primer": "^2.0.0",
45+
"unist-util-find-before": "^2.0.1",
46+
"unist-util-parents": "^1.0.0",
47+
"unist-util-select": "^1.5.0",
4148
"yo": "^2.0.0"
4249
}
4350
}

0 commit comments

Comments
 (0)