Skip to content

Commit

Permalink
Feat: Page per section (#835)
Browse files Browse the repository at this point in the history
Closes #494, #768.
  • Loading branch information
bitionaire authored and sapegin committed Mar 21, 2018
1 parent fb1d2ec commit 6055c2b
Show file tree
Hide file tree
Showing 22 changed files with 398 additions and 61 deletions.
17 changes: 17 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ By default, Styleguidist will look for `styleguide.config.js` file in your proje
* [`handlers`](#handlers)
* [`ignore`](#ignore)
* [`logger`](#logger)
* [`pagePerSection`](#pagepersection)
* [`previewDelay`](#previewdelay)
* [`propsParser`](#propsparser)
* [`require`](#require)
Expand Down Expand Up @@ -261,6 +262,22 @@ module.exports = {
}
```

#### `pagePerSection`

Type: `Boolean`, default: `false`

Render one section or component per page, starting with the first.

If set to `true`, the sidebar will be visible on each page, except for the examples.

The value may be differ on each environment.

```javascript
module.exports = {
pagePerSection: process.env.NODE_ENV !== 'production'
}
```

#### `previewDelay`

Type: `Number`, default: 500
Expand Down
1 change: 1 addition & 0 deletions loaders/styleguide-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const CLIENT_CONFIG_OPTIONS = [
'styles',
'compilerConfig',
'editorConfig',
'pagePerSection',
];

module.exports = function() {};
Expand Down
4 changes: 4 additions & 0 deletions scripts/schemas/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ module.exports = {
logger: {
type: 'object',
},
pagePerSection: {
type: 'boolean',
default: false,
},
previewDelay: {
type: 'number',
default: 500,
Expand Down
10 changes: 9 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
/* eslint-disable import/first */

import './polyfills';
import './styles';
import ReactDOM from 'react-dom';
import renderStyleguide from './utils/renderStyleguide';

// Examples code revision to rerender only code examples (not the whole page) when code changes
// eslint-disable-next-line no-unused-vars
let codeRevision = 0;

/** Scrolls to origin when current window location hash points to an isolated view. */
const scrollToOrigin = () => {
if (window.location.hash.indexOf('#!/') === 0) {
window.scrollTo(0, 0);
}
};

const render = () => {
// eslint-disable-next-line import/no-unresolved
const styleguide = require('!!../loaders/styleguide-loader!./index.js');
ReactDOM.render(renderStyleguide(styleguide, codeRevision), document.getElementById('app'));
};

window.addEventListener('hashchange', render);
window.addEventListener('hashchange', scrollToOrigin);

/* istanbul ignore if */
if (module.hot) {
Expand Down
25 changes: 25 additions & 0 deletions src/rsg-components/ComponentsList/ComponentsList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import ComponentsListRenderer from 'rsg-components/ComponentsList/ComponentsListRenderer';
import PropTypes from 'prop-types';
import getUrl from '../../utils/getUrl';

function ComponentsList({ classes, items, useIsolatedLinks = false }) {
const mappedItems = items.map(item => ({
...item,
href: getUrl({
name: item.name,
slug: item.slug,
anchor: !useIsolatedLinks,
isolated: useIsolatedLinks,
}),
}));
return <ComponentsListRenderer classes={classes} items={mappedItems} />;
}

ComponentsList.propTypes = {
items: PropTypes.array.isRequired,
classes: PropTypes.object,
useIsolatedLinks: PropTypes.bool,
};

export default ComponentsList;
37 changes: 37 additions & 0 deletions src/rsg-components/ComponentsList/ComponentsList.spec.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,50 @@
import React from 'react';
import ComponentsList from './ComponentsList';
import { ComponentsListRenderer } from './ComponentsListRenderer';

it('should set the correct href for items', () => {
const components = [
{
name: 'Button',
slug: 'button',
},
{
name: 'Input',
slug: 'input',
},
];

const actual = shallow(<ComponentsList items={components} classes={{}} />);
expect(actual).toMatchSnapshot();
});

it('should set the correct href for items when isolated links should be used', () => {
const components = [
{
name: 'Button',
slug: 'button',
},
{
name: 'Input',
slug: 'input',
},
];

const actual = shallow(<ComponentsList items={components} classes={{}} useIsolatedLinks />);
expect(actual).toMatchSnapshot();
});

it('should render sections with nested components', () => {
const components = [
{
name: 'Button',
slug: 'button',
href: '#button',
},
{
name: 'Input',
slug: 'input',
href: '#input',
},
];
const actual = shallow(<ComponentsListRenderer items={components} classes={{}} />);
Expand All @@ -28,9 +63,11 @@ it('should ignore items without name', () => {
{
name: 'Button',
slug: 'button',
href: '#button',
},
{
slug: 'input',
href: '#input',
},
];
const actual = shallow(<ComponentsListRenderer items={components} classes={{}} />);
Expand Down
5 changes: 3 additions & 2 deletions src/rsg-components/ComponentsList/ComponentsListRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ export function ComponentsListRenderer({ classes, items }) {

return (
<ul className={classes.list}>
{items.map(({ heading, name, slug, content }) => (
{items.map(({ heading, name, href, content }) => (
<li
className={cx(classes.item, (!content || !content.props.items.length) && classes.isChild)}
key={name}
>
<Link className={cx(heading && classes.heading)} href={`#${slug}`}>
<Link className={cx(heading && classes.heading)} href={href}>
{name}
</Link>
{content}
Expand All @@ -60,6 +60,7 @@ export function ComponentsListRenderer({ classes, items }) {
ComponentsListRenderer.propTypes = {
items: PropTypes.array.isRequired,
classes: PropTypes.object.isRequired,
useIsolatedLinks: PropTypes.bool,
};

export default Styled(styles)(ComponentsListRenderer);
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,43 @@ exports[`should render sections with nested components 1`] = `
</li>
</ul>
`;

exports[`should set the correct href for items 1`] = `
<Styled(ComponentsList)
classes={Object {}}
items={
Array [
Object {
"href": "blank#button",
"name": "Button",
"slug": "button",
},
Object {
"href": "blank#input",
"name": "Input",
"slug": "input",
},
]
}
/>
`;

exports[`should set the correct href for items when isolated links should be used 1`] = `
<Styled(ComponentsList)
classes={Object {}}
items={
Array [
Object {
"href": "blank#!/Button",
"name": "Button",
"slug": "button",
},
Object {
"href": "blank#!/Input",
"name": "Input",
"slug": "input",
},
]
}
/>
`;
2 changes: 1 addition & 1 deletion src/rsg-components/ComponentsList/index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { default } from 'rsg-components/ComponentsList/ComponentsListRenderer';
export { default } from 'rsg-components/ComponentsList/ComponentsList';
2 changes: 1 addition & 1 deletion src/rsg-components/Playground/Playground.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const options = {
highlightTheme: 'base16-light',
},
codeRevision: 0,
slots,
slots: slots({}),
},
childContextTypes: {
slots: PropTypes.object.isRequired,
Expand Down
39 changes: 36 additions & 3 deletions src/rsg-components/StyleGuide/StyleGuide.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,29 @@ import Error from 'rsg-components/Error';
import { HOMEPAGE } from '../../../scripts/consts';
import { DisplayModes } from '../../consts';

/**
* This function will return true, if the sidebar should be visible and false otherwise.
*
* These sorted conditions (highest precedence first) define the visibility
* state of the sidebar.
*
* - Sidebar is hidden for isolated example views
* - Sidebar is always visible when pagePerSection
* - Sidebar is hidden when showSidebar is set to false
* - Sidebar is visible when showSidebar is set to true for non-isolated views
*
* @param {boolean} displayMode
* @param {boolean} showSidebar
* @param {boolean} pagePerSection
* @returns {boolean}
*/
function hasSidebar(displayMode, showSidebar, pagePerSection = false) {
return (
(pagePerSection && displayMode !== DisplayModes.example) ||
(showSidebar && displayMode === DisplayModes.all)
);
}

export default class StyleGuide extends Component {
static propTypes = {
codeRevision: PropTypes.number.isRequired,
Expand All @@ -17,6 +40,8 @@ export default class StyleGuide extends Component {
welcomeScreen: PropTypes.bool,
patterns: PropTypes.array,
displayMode: PropTypes.string,
allSections: PropTypes.array.isRequired,
pagePerSection: PropTypes.bool,
};

static childContextTypes = {
Expand Down Expand Up @@ -52,7 +77,15 @@ export default class StyleGuide extends Component {
}

render() {
const { config, sections, welcomeScreen, patterns, displayMode } = this.props;
const {
config,
sections,
welcomeScreen,
patterns,
displayMode,
allSections,
pagePerSection,
} = this.props;

if (this.state.error) {
return <Error error={this.state.error} info={this.state.info} />;
Expand All @@ -66,8 +99,8 @@ export default class StyleGuide extends Component {
<StyleGuideRenderer
title={config.title}
homepageUrl={HOMEPAGE}
toc={<TableOfContents sections={sections} />}
hasSidebar={config.showSidebar && displayMode === DisplayModes.all}
toc={<TableOfContents sections={allSections} useIsolatedLinks={pagePerSection} />}
hasSidebar={hasSidebar(displayMode, config.showSidebar, pagePerSection)}
>
<Sections sections={sections} depth={1} />
</StyleGuideRenderer>
Expand Down
Loading

0 comments on commit 6055c2b

Please sign in to comment.