Skip to content

Commit db815e5

Browse files
Knorcedgersapegin
authored andcommitted
Feat: Section isolated mode (#394)
1 parent b0dd5f1 commit db815e5

File tree

7 files changed

+152
-39
lines changed

7 files changed

+152
-39
lines changed

src/index.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import React from 'react';
33
import ReactDOM from 'react-dom';
44
import isFinite from 'lodash/isFinite';
55
import {
6-
getComponentNameFromHash,
6+
getInfoFromHash,
77
filterComponentExamples,
88
filterComponentsInSectionsByExactName,
9+
filterSections,
910
processSections,
1011
setSlugs,
1112
slugger,
@@ -27,24 +28,31 @@ function renderStyleguide() {
2728

2829
// Parse URL hash to check if the components list must be filtered
2930
const {
30-
// Name of the filtered component to show isolated (/#!/Button → Button)
31-
targetComponentName,
31+
// Name of the filtered component/section to show isolated (/#!/Button → Button)
32+
targetName,
3233
// Index of the fenced block example of the filtered component isolate (/#!/Button/1 → 1)
33-
targetComponentIndex,
34-
} = getComponentNameFromHash();
34+
targetIndex,
35+
} = getInfoFromHash();
3536

3637
let isolatedComponent = false;
3738
let isolatedExample = false;
39+
let isolatedSection = false;
3840

3941
// Filter the requested component id required
40-
if (targetComponentName) {
41-
const filteredComponents = filterComponentsInSectionsByExactName(sections, targetComponentName);
42-
sections = [{ components: filteredComponents }];
43-
isolatedComponent = true;
42+
if (targetName) {
43+
const filteredComponents = filterComponentsInSectionsByExactName(sections, targetName);
44+
if (filteredComponents.length) {
45+
sections = [{ components: filteredComponents }];
46+
isolatedComponent = true;
47+
}
48+
else {
49+
sections = [filterSections(sections, targetName)];
50+
isolatedSection = true;
51+
}
4452

4553
// If a single component is filtered and a fenced block index is specified hide the other examples
46-
if (filteredComponents.length === 1 && isFinite(targetComponentIndex)) {
47-
filteredComponents[0] = filterComponentExamples(filteredComponents[0], targetComponentIndex);
54+
if (filteredComponents.length === 1 && isFinite(targetIndex)) {
55+
filteredComponents[0] = filterComponentExamples(filteredComponents[0], targetIndex);
4856
isolatedExample = true;
4957
}
5058
}
@@ -62,6 +70,7 @@ function renderStyleguide() {
6270
sections={sections}
6371
isolatedComponent={isolatedComponent}
6472
isolatedExample={isolatedExample}
73+
isolatedSection={isolatedSection}
6574
/>,
6675
document.getElementById('app')
6776
);

src/rsg-components/Section/Section.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Components from 'rsg-components/Components';
55
import Sections from 'rsg-components/Sections';
66
import SectionRenderer from 'rsg-components/Section/SectionRenderer';
77

8-
export default function Section({ section }) {
8+
export default function Section({ section }, { isolatedSection = false }) {
99
const { name, slug, content, components, sections } = section;
1010

1111
const contentJsx = content && (
@@ -21,17 +21,23 @@ export default function Section({ section }) {
2121
sections={sections}
2222
/>
2323
);
24+
2425
return (
2526
<SectionRenderer
2627
name={name}
2728
slug={slug}
2829
content={contentJsx}
2930
components={componentsJsx}
3031
sections={sectionsJsx}
32+
isolatedSection={isolatedSection}
3133
/>
3234
);
3335
}
3436

3537
Section.propTypes = {
3638
section: PropTypes.object.isRequired,
3739
};
40+
41+
Section.contextTypes = {
42+
isolatedSection: PropTypes.bool,
43+
};

src/rsg-components/Section/SectionRenderer.js

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,52 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import Styled from 'rsg-components/Styled';
44
import Heading from 'rsg-components/Heading';
5+
import Link from 'rsg-components/Link';
56

67
const styles = ({ space, fontFamily, fontSize }) => ({
78
root: {
89
marginBottom: space[4],
10+
'&:hover $isolatedLink': {
11+
isolate: false,
12+
opacity: 1,
13+
},
914
},
1015
heading: {
1116
margin: [[0, 0, space[2]]],
1217
fontFamily: fontFamily.base,
1318
fontSize: fontSize.h1,
1419
},
20+
isolatedLink: {
21+
position: 'absolute',
22+
top: 0,
23+
right: 0,
24+
fontFamily: fontFamily.base,
25+
fontSize: fontSize.base,
26+
opacity: 0,
27+
transition: 'opacity ease-in-out .15s .2s',
28+
},
29+
titleWrapper: {
30+
position: 'relative',
31+
},
1532
});
1633

17-
export function SectionRenderer({ classes, name, slug, content, components, sections }) {
34+
export function SectionRenderer({ classes, name, slug, content, components, sections, isolatedSection }) {
1835
return (
1936
<section className={classes.root}>
20-
{name && (
21-
<Heading level={1} slug={slug} className={classes.heading}>{name}</Heading>
22-
)}
37+
<div className={classes.titleWrapper}>
38+
{name && (
39+
<Heading level={1} slug={slug} className={classes.heading}>{name}</Heading>
40+
)}
41+
<div className={classes.isolatedLink}>
42+
{name && (
43+
isolatedSection ? (
44+
<Link href="/">⇽ Back</Link>
45+
) : (
46+
<Link href={'#!/' + name}>Open isolated ⇢</Link>
47+
)
48+
)}
49+
</div>
50+
</div>
2351
{content}
2452
{components}
2553
{sections}
@@ -34,6 +62,7 @@ SectionRenderer.propTypes = {
3462
content: PropTypes.node,
3563
components: PropTypes.node,
3664
sections: PropTypes.node,
65+
isolatedSection: PropTypes.bool,
3766
};
3867

3968
export default Styled(styles)(SectionRenderer);

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

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`render should not render title if name is not set 1`] = `<section />`;
3+
exports[`render should not render title if name is not set 1`] = `
4+
<section>
5+
<div>
6+
<div />
7+
</div>
8+
</section>
9+
`;
410

511
exports[`render should render component 1`] = `
612
<section>
7-
<_class
8-
level={1}
9-
slug="foo"
10-
>
11-
Foo
12-
</_class>
13+
<div>
14+
<_class
15+
level={1}
16+
slug="foo"
17+
>
18+
Foo
19+
</_class>
20+
<div>
21+
<_class
22+
href="#!/Foo"
23+
>
24+
Open isolated ⇢
25+
</_class>
26+
</div>
27+
</div>
1328
<Examples
1429
examples={
1530
Array [
@@ -36,24 +51,35 @@ exports[`render should render component 1`] = `
3651

3752
exports[`render should render title if name is set 1`] = `
3853
<section>
39-
<_class
40-
level={1}
41-
slug="test"
42-
>
43-
test
44-
</_class>
54+
<div>
55+
<_class
56+
level={1}
57+
slug="test"
58+
>
59+
test
60+
</_class>
61+
<div>
62+
<_class
63+
href="#!/test"
64+
>
65+
Open isolated ⇢
66+
</_class>
67+
</div>
68+
</div>
4569
</section>
4670
`;
4771

4872
exports[`should not render components list if not defined 1`] = `
4973
<_class
74+
isolatedSection={false}
5075
name="No components"
5176
slug="no-components"
5277
/>
5378
`;
5479

5580
exports[`should not render sections if not defined 1`] = `
5681
<_class
82+
isolatedSection={false}
5783
name="No sections"
5884
slug="no-sections"
5985
/>
@@ -83,6 +109,7 @@ exports[`should render component renderer 1`] = `
83109
}
84110
/>
85111
}
112+
isolatedSection={false}
86113
name="Foo"
87114
sections={
88115
<Sections
@@ -100,13 +127,15 @@ exports[`should render components list 1`] = `
100127
components={Array []}
101128
/>
102129
}
130+
isolatedSection={false}
103131
name="Components"
104132
slug="components"
105133
/>
106134
`;
107135

108136
exports[`should render sections if defined 1`] = `
109137
<_class
138+
isolatedSection={false}
110139
name="Nested sections"
111140
sections={
112141
<Sections

src/rsg-components/StyleGuide/StyleGuide.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ export default class StyleGuide extends Component {
1515
patterns: PropTypes.array,
1616
isolatedComponent: PropTypes.bool,
1717
isolatedExample: PropTypes.bool,
18+
isolatedSection: PropTypes.bool,
1819
};
1920

2021
static childContextTypes = {
2122
codeKey: PropTypes.number.isRequired,
2223
config: PropTypes.object.isRequired,
2324
isolatedComponent: PropTypes.bool,
2425
isolatedExample: PropTypes.bool,
26+
isolatedSection: PropTypes.bool,
2527
};
2628

2729
static defaultProps = {
@@ -34,6 +36,7 @@ export default class StyleGuide extends Component {
3436
config: this.props.config,
3537
isolatedComponent: this.props.isolatedComponent,
3638
isolatedExample: this.props.isolatedExample,
39+
isolatedSection: this.props.isolatedSection,
3740
};
3841
}
3942

src/utils/__tests__/utils.spec.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,18 +243,45 @@ describe('filterSectionsByName', () => {
243243
});
244244
});
245245

246-
describe('getComponentNameFromHash', () => {
246+
describe('getInfoFromHash', () => {
247247
it('should return important part of hash if it contains component name', () => {
248-
const result = utils.getComponentNameFromHash('#!/Button');
249-
expect(result).toEqual({ targetComponentName: 'Button', targetComponentIndex: null });
248+
const result = utils.getInfoFromHash('#!/Button');
249+
expect(result).toEqual({ targetName: 'Button', targetIndex: null });
250250
});
251251

252252
it('should return an empty object if hash contains no component name', () => {
253-
const result = utils.getComponentNameFromHash('Button');
253+
const result = utils.getInfoFromHash('Button');
254254
expect(result).toEqual({});
255255
});
256256
});
257257

258+
describe('filterSections', () => {
259+
const sections = [
260+
{
261+
name: 'General',
262+
sections: [],
263+
},
264+
{
265+
name: 'Forms',
266+
sections: [],
267+
},
268+
{
269+
name: 'Lists',
270+
sections: [],
271+
},
272+
];
273+
274+
it('should return the Forms section', () => {
275+
const result = utils.filterSections(sections, 'Forms');
276+
expect(result).toEqual(sections[1]);
277+
});
278+
279+
it('should return the Lists section', () => {
280+
const result = utils.filterSections(sections, 'Lists');
281+
expect(result).toEqual(sections[2]);
282+
});
283+
});
284+
258285
describe('filterComponentExamples', () => {
259286
it('should return a shallow copy of the component with example filtered by given index', () => {
260287
const comp = {

src/utils/utils.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,21 +149,31 @@ export function filterComponentsInSectionsByExactName(sections, name) {
149149
}
150150

151151
/**
152-
* Returns an object containing component name and, optionally, an example index
152+
* Filters the sections to find the one with the matching name
153+
* @param {Array} sections The styleguide sections
154+
* @param {string} name The name to match
155+
* @return {object} The section found
156+
*/
157+
export function filterSections(sections, name) {
158+
return sections.find(section => section.name === name);
159+
}
160+
161+
/**
162+
* Returns an object containing component/section name and, optionally, an example index
153163
* from hash part or page URL:
154-
* http://localhost:6060/#!/Button → { targetComponentName: 'Button' }
155-
* http://localhost:6060/#!/Button/1 → { targetComponentName: 'Button', targetComponentIndex: 1 }
164+
* http://localhost:6060/#!/Button → { targetName: 'Button' }
165+
* http://localhost:6060/#!/Button/1 → { targetName: 'Button', targetIndex: 1 }
156166
*
157167
* @param {string} [hash]
158168
* @returns {object}
159169
*/
160-
export function getComponentNameFromHash(hash = window.location.hash) {
170+
export function getInfoFromHash(hash = window.location.hash) {
161171
if (hash.substr(0, 3) === '#!/') {
162172
const tokens = hash.substr(3).split('/');
163173
const index = parseInt(tokens[1], 10);
164174
return {
165-
targetComponentName: tokens[0],
166-
targetComponentIndex: isNaN(index) ? null : index,
175+
targetName: tokens[0],
176+
targetIndex: isNaN(index) ? null : index,
167177
};
168178
}
169179
return {};

0 commit comments

Comments
 (0)