Skip to content

Commit 5eaae36

Browse files
glebezsapegin
authored andcommitted
Feat: 'Fork me' ribbon (#861)
Part of #195, closes #647.
1 parent 3ebcc80 commit 5eaae36

File tree

13 files changed

+170
-2
lines changed

13 files changed

+170
-2
lines changed

docs/Configuration.md

+16
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ By default, Styleguidist will look for `styleguide.config.js` file in your proje
2525
* [`propsParser`](#propsparser)
2626
* [`require`](#require)
2727
* [`resolver`](#resolver)
28+
* [`ribbon`](#ribbon)
2829
* [`sections`](#sections)
2930
* [`serverHost`](#serverhost)
3031
* [`serverPort`](#serverport)
@@ -347,6 +348,21 @@ module.exports = {
347348
}
348349
```
349350

351+
#### `ribbon`
352+
353+
Type: `Object`, optional
354+
355+
Shows 'Fork Me' ribbon in the top-right corner. If `ribbon` key is present, then it's required to add `url` property; `text` property is optional. If you want to change styling of the ribbon, please, refer to the [theme section](#theme).
356+
357+
```javascript
358+
module.exports = {
359+
ribbon: {
360+
url: 'http://example.com/',
361+
text: 'Fork me on GitHub',
362+
}
363+
};
364+
```
365+
350366
#### `sections`
351367

352368
Type: `Array`, optional

examples/basic/styleguide.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
module.exports = {
22
components: 'src/components/**/[A-Z]*.js',
33
defaultExample: true,
4+
ribbon: {
5+
url: 'https://github.com/styleguidist/react-styleguidist',
6+
},
47
webpackConfig: {
58
module: {
69
rules: [

loaders/styleguide-loader.js

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const CLIENT_CONFIG_OPTIONS = [
2424
'styles',
2525
'compilerConfig',
2626
'editorConfig',
27+
'ribbon',
2728
'pagePerSection',
2829
];
2930

scripts/schemas/config.js

+7
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ module.exports = {
150150
return annotatedComponents.concat(exportedComponents);
151151
},
152152
},
153+
ribbon: {
154+
type: 'object',
155+
example: {
156+
url: 'http://example.com/',
157+
text: 'Fork me on GitHub',
158+
},
159+
},
153160
sections: {
154161
type: 'array',
155162
default: [],

src/rsg-components/Ribbon/Ribbon.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import RibbonRenderer from 'rsg-components/Ribbon/RibbonRenderer';
4+
5+
export default function Ribbon({}, { config }) {
6+
const { ribbon } = config;
7+
return ribbon ? <RibbonRenderer {...ribbon} /> : null;
8+
}
9+
10+
Ribbon.contextTypes = {
11+
config: PropTypes.object,
12+
};
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react';
2+
import Ribbon from './Ribbon';
3+
import { RibbonRenderer, styles } from './RibbonRenderer';
4+
5+
const props = {
6+
classes: classes(styles),
7+
};
8+
9+
describe('Ribbon', () => {
10+
it('should render ribbon if the ribbon is present in the config', () => {
11+
const actual = shallow(<Ribbon />, { context: { config: { ribbon: { url: 'foo.bar' } } } });
12+
13+
expect(actual).toMatchSnapshot();
14+
});
15+
16+
it('should return null if the ribbon is not present in the config', () => {
17+
const actual = shallow(<Ribbon />, { context: { config: {} } });
18+
19+
expect(actual.type()).toBeNull();
20+
});
21+
});
22+
describe('RibbonRenderer', () => {
23+
it('should render ribbon with url', () => {
24+
const actual = shallow(<RibbonRenderer {...props} url="http://example.com" />);
25+
26+
expect(actual).toMatchSnapshot();
27+
});
28+
29+
it('should render ribbon with a text', () => {
30+
const actual = shallow(
31+
<RibbonRenderer {...props} url="http://example.com" text="Share the repo" />
32+
);
33+
34+
expect(actual).toMatchSnapshot();
35+
});
36+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import Styled from 'rsg-components/Styled';
4+
5+
export const styles = ({ color, space, fontSize, fontFamily }) => ({
6+
root: {
7+
position: 'fixed',
8+
top: 0,
9+
right: 0,
10+
width: 149,
11+
height: 149,
12+
zIndex: 999,
13+
},
14+
link: {
15+
fontFamily: fontFamily.base,
16+
position: 'relative',
17+
right: -37,
18+
top: -22,
19+
display: 'block',
20+
width: 190,
21+
padding: [[space[0], space[2]]],
22+
textAlign: 'center',
23+
color: color.ribbonText,
24+
fontSize: fontSize.base,
25+
background: color.ribbonBackground,
26+
textDecoration: 'none',
27+
textShadow: [[0, '-1px', 0, 'rgba(0,0,0,.15)']],
28+
transformOrigin: [[0, 0]],
29+
transform: 'rotate(45deg)',
30+
cursor: 'pointer',
31+
},
32+
});
33+
34+
export function RibbonRenderer({ classes, url, text }) {
35+
return (
36+
<div className={classes.root}>
37+
<a href={url} className={classes.link}>
38+
{text}
39+
</a>
40+
</div>
41+
);
42+
}
43+
44+
RibbonRenderer.defaultProps = {
45+
text: 'Fork me on GitHub',
46+
};
47+
48+
RibbonRenderer.propTypes = {
49+
classes: PropTypes.object.isRequired,
50+
url: PropTypes.string.isRequired,
51+
text: PropTypes.string,
52+
};
53+
54+
export default Styled(styles)(RibbonRenderer);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Ribbon should render ribbon if the ribbon is present in the config 1`] = `
4+
<Styled(Ribbon)
5+
url="foo.bar"
6+
/>
7+
`;
8+
9+
exports[`RibbonRenderer should render ribbon with a text 1`] = `
10+
<div
11+
className="root"
12+
>
13+
<a
14+
className="link"
15+
href="http://example.com"
16+
>
17+
Share the repo
18+
</a>
19+
</div>
20+
`;
21+
22+
exports[`RibbonRenderer should render ribbon with url 1`] = `
23+
<div
24+
className="root"
25+
>
26+
<a
27+
className="link"
28+
href="http://example.com"
29+
>
30+
Fork me on GitHub
31+
</a>
32+
</div>
33+
`;

src/rsg-components/Ribbon/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from 'rsg-components/Ribbon/Ribbon.js';

src/rsg-components/StyleGuide/StyleGuide.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ describe('sidebar rendering', () => {
135135
});
136136
});
137137

138-
it('renderer should render logo, table of contents and passed children', () => {
138+
it('renderer should render logo, table of contents, ribbon and passed children', () => {
139139
const actual = shallow(
140140
<StyleGuideRenderer
141141
classes={{}}

src/rsg-components/StyleGuide/StyleGuideRenderer.js

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Logo from 'rsg-components/Logo';
44
import Markdown from 'rsg-components/Markdown';
55
import Styled from 'rsg-components/Styled';
66
import cx from 'classnames';
7+
import Ribbon from 'rsg-components/Ribbon';
78

89
const styles = ({ color, fontFamily, fontSize, sidebarWidth, mq, space, maxWidth }) => ({
910
root: {
@@ -71,6 +72,7 @@ export function StyleGuideRenderer({ classes, title, homepageUrl, children, toc,
7172
{toc}
7273
</div>
7374
)}
75+
<Ribbon />
7476
</div>
7577
);
7678
}

src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`renderer should render logo, table of contents and passed children 1`] = `
3+
exports[`renderer should render logo, table of contents, ribbon and passed children 1`] = `
44
<div
55
className=""
66
>
@@ -47,6 +47,7 @@ exports[`renderer should render logo, table of contents and passed children 1`]
4747
}
4848
/>
4949
</div>
50+
<Ribbon />
5051
</div>
5152
`;
5253

src/styles/theme.js

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export const color = {
2222
baseBackground: '#fff',
2323
codeBackground: '#f5f5f5',
2424
sidebarBackground: '#f5f5f5',
25+
ribbonBackground: '#f9970d',
26+
ribbonText: '#fff',
2527
};
2628

2729
export const fontFamily = {

0 commit comments

Comments
 (0)