Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(ComponentSidebar): add sidebar navigation #2070

Merged
merged 17 commits into from
Nov 25, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
coverage/
dist/
docs/app/docgenInfo.json
docs/app/menuInfo.json
docs/build/
dll/
node_modules/
145 changes: 102 additions & 43 deletions docs/app/Components/ComponentDoc/ComponentDoc.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,115 @@
import _ from 'lodash'
import PropTypes from 'prop-types'
import React from 'react'
import React, { Component } from 'react'
import DocumentTitle from 'react-document-title'
import { withRouter } from 'react-router'
import { Grid } from 'semantic-ui-react'

import { withDocInfo } from 'docs/app/HOC'
import { scrollToAnchor } from 'docs/app/utils'
import ComponentDocHeader from './ComponentDocHeader'
import ComponentDocLinks from './ComponentDocLinks'
import ComponentDocSee from './ComponentDocSee'
import ComponentExamples from './ComponentExamples'
import ComponentProps from './ComponentProps'
import ComponentSidebar from './ComponentSidebar'

const ComponentDoc = ({ componentGroup, componentName, description, ghLink, path, seeItems, suiLink }) => (
<DocumentTitle title={`${componentName} | Semantic UI React`}>
<div>
<Grid padded columns='1'>
<Grid.Column>
<ComponentDocHeader componentName={componentName} description={description} />
<ComponentDocSee items={seeItems} />
<ComponentDocLinks
componentName={componentName}
ghLink={ghLink}
path={path}
suiLink={suiLink}
/>
<ComponentProps componentGroup={componentGroup} componentName={componentName} />
</Grid.Column>
</Grid>

<ComponentExamples componentName={componentName} />
</div>
</DocumentTitle>
)

ComponentDoc.propTypes = {
componentGroup: PropTypes.arrayOf(
PropTypes.shape({
description: PropTypes.string,
props: PropTypes.object,
}),
),
componentName: PropTypes.string.isRequired,
description: PropTypes.string,
ghLink: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
seeItems: PropTypes.arrayOf(
PropTypes.shape({
description: PropTypes.string,
name: PropTypes.string,
type: PropTypes.string,
}),
).isRequired,
suiLink: PropTypes.string,
const topRowStyle = { margin: '1em' }

class ComponentDoc extends Component {
static childContextTypes = {
onPassed: PropTypes.func,
}

static propTypes = {
componentGroup: PropTypes.arrayOf(
PropTypes.shape({
description: PropTypes.string,
props: PropTypes.object,
}),
),
componentName: PropTypes.string.isRequired,
description: PropTypes.string,
ghLink: PropTypes.string.isRequired,
history: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
seeItems: PropTypes.arrayOf(
PropTypes.shape({
description: PropTypes.string,
name: PropTypes.string,
type: PropTypes.string,
}),
).isRequired,
suiLink: PropTypes.string,
}

state = {}

getChildContext() {
return {
onPassed: this.handleExamplePassed,
}
}

componentWillReceiveProps({ componentName: next }) {
const { componentName: current } = this.props

if (current !== next) this.setState({ activePath: undefined })
}

handleExamplePassed = (e, { examplePath }) => this.setState({ activePath: examplePath })

handleExamplesRef = examplesRef => this.setState({ examplesRef })

handleSidebarItemClick = (e, { path }) => {
const { history } = this.props
const aPath = _.kebabCase(_.last(path.split('/')))

history.replace(`${location.pathname}#${aPath}`)
scrollToAnchor()
}

render() {
const { componentGroup, componentName, description, ghLink, path, seeItems, suiLink } = this.props
const { activePath, examplesRef } = this.state

return (
<DocumentTitle title={`${componentName} | Semantic UI React`}>
<Grid>
<Grid.Row columns='equal' style={topRowStyle}>
<Grid.Column>
<ComponentDocHeader componentName={componentName} description={description} />
<ComponentDocSee items={seeItems} />
<ComponentDocLinks
componentName={componentName}
ghLink={ghLink}
path={path}
suiLink={suiLink}
/>
<ComponentProps componentGroup={componentGroup} componentName={componentName} />
</Grid.Column>
<Grid.Column computer={5} largeScreen={4} widescreen={4} />
</Grid.Row>

<Grid.Row columns='equal'>
<Grid.Column>
<div ref={this.handleExamplesRef}>
<ComponentExamples componentName={componentName} />
</div>
</Grid.Column>
<Grid.Column computer={5} largeScreen={4} widescreen={4}>
<ComponentSidebar
activePath={activePath}
componentName={componentName}
examplesRef={examplesRef}
onItemClick={this.handleSidebarItemClick}
/>
</Grid.Column>
</Grid.Row>
</Grid>
</DocumentTitle>
)
}
}

export default withDocInfo(ComponentDoc)
export default withDocInfo(withRouter(ComponentDoc))
112 changes: 67 additions & 45 deletions docs/app/Components/ComponentDoc/ComponentExample/ComponentExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { html } from 'js-beautify'
import copyToClipboard from 'copy-to-clipboard'

import { exampleContext, repoURL, scrollToAnchor } from 'docs/app/utils'
import { Divider, Grid, Menu } from 'src'
import { Divider, Grid, Menu, Visibility } from 'src'
import { shallowEqual } from 'src/lib'
import Editor from 'docs/app/Components/Editor/Editor'
import ComponentControls from '../ComponentControls'
import ComponentExampleTitle from './ComponentExampleTitle'
Expand Down Expand Up @@ -40,6 +41,10 @@ const errorStyle = {
* Allows toggling the the raw `code` code block.
*/
class ComponentExample extends Component {
static contextTypes = {
onPassed: PropTypes.func,
}

static propTypes = {
children: PropTypes.node,
description: PropTypes.node,
Expand Down Expand Up @@ -70,8 +75,13 @@ class ComponentExample extends Component {
})
}

shouldComponentUpdate(nextProps, nextState) {
Copy link
Member Author

@layershifter layershifter Sep 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small optimization. Without it, all examples will be rerendered

return !shallowEqual(this.state, nextState)
}

setHashAndScroll = () => {
const { history } = this.props

history.replace(`${location.pathname}#${this.anchorName}`)
scrollToAnchor()
}
Expand Down Expand Up @@ -110,6 +120,12 @@ class ComponentExample extends Component {
else this.removeHash()
}

handlePass = () => {
const { title } = this.props

if (title) _.invoke(this.context, 'onPassed', null, this.props)
}

copyJSX = () => {
copyToClipboard(this.state.sourceCode)
this.setState({ copiedCode: true })
Expand Down Expand Up @@ -381,52 +397,58 @@ class ComponentExample extends Component {
}

return (
<Grid
className='docs-example'
id={this.anchorName}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
style={exampleStyle}
<Visibility
once={false}
onTopPassed={this.handlePass}
onTopPassedReverse={this.handlePass}
>
<Grid.Row>
<Grid.Column style={headerColumnStyle} width={12}>
<ComponentExampleTitle
description={description}
title={title}
suiVersion={suiVersion}
/>
</Grid.Column>
<Grid.Column textAlign='right' width={4}>
<ComponentControls
anchorName={this.anchorName}
onCopyLink={this.handleDirectLinkClick}
onShowCode={this.handleShowCodeClick}
onShowHTML={this.handleShowHTMLClick}
showCode={showCode}
showHTML={showHTML}
visible={controlsVisible}
/>
</Grid.Column>
</Grid.Row>

<Grid.Row columns={1}>
{children && (
<Grid.Column style={childrenStyle}>
{children}
<Grid
className='docs-example'
id={this.anchorName}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
style={exampleStyle}
>
<Grid.Row>
<Grid.Column style={headerColumnStyle} width={12}>
<ComponentExampleTitle
description={description}
title={title}
suiVersion={suiVersion}
/>
</Grid.Column>
<Grid.Column textAlign='right' width={4}>
<ComponentControls
anchorName={this.anchorName}
onCopyLink={this.handleDirectLinkClick}
onShowCode={this.handleShowCodeClick}
onShowHTML={this.handleShowHTMLClick}
showCode={showCode}
showHTML={showHTML}
visible={controlsVisible}
/>
</Grid.Column>
</Grid.Row>

<Grid.Row columns={1}>
{children && (
<Grid.Column style={childrenStyle}>
{children}
</Grid.Column>
)}
</Grid.Row>

<Grid.Row columns={1}>
<Grid.Column className={`rendered-example ${this.getKebabExamplePath()}`}>
{exampleElement}
</Grid.Column>
<Grid.Column>
{this.renderJSX()}
{this.renderHTML()}
</Grid.Column>
)}
</Grid.Row>

<Grid.Row columns={1}>
<Grid.Column className={`rendered-example ${this.getKebabExamplePath()}`}>
{exampleElement}
</Grid.Column>
<Grid.Column>
{this.renderJSX()}
{this.renderHTML()}
</Grid.Column>
</Grid.Row>
</Grid>
</Grid.Row>
</Grid>
</Visibility>
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import _ from 'lodash'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { Accordion, Menu, Sticky } from 'semantic-ui-react'

import menuInfo from 'docs/app/menuInfo.json'
import ComponentSideBarSection from './ComponentSidebarSection'

const sidebarStyle = {
background: '#fff',
boxShadow: '0 2px 2px rgba(0, 0, 0, 0.1)',
paddingLeft: '1em',
paddingBottom: '0.1em',
paddingTop: '0.1em',
}

class ComponentSidebar extends Component {
static propTypes = {
activePath: PropTypes.string,
componentName: PropTypes.string,
examplesRef: PropTypes.func,
onItemClick: PropTypes.func,
}

state = {}

constructor(props) {
super(props)

this.state = { sections: this.computeSections(props) }
}

componentWillReceiveProps(nextProps) {
this.setState({ sections: this.computeSections(nextProps) })
}

computeSections = ({ componentName }) => _.get(menuInfo, componentName)

handleItemClick = (e, { path }) => _.invoke(this.props, 'onItemClick', e, { path })

handleTitleClick = (e, { name }) => {
const { sections } = this.state
const { examples } = _.find(sections, { name })
const { path } = _.head(examples)

_.invoke(this.props, 'onItemClick', e, { path })
}

render() {
const { activePath, examplesRef } = this.props
const { sections } = this.state

return (
<Sticky context={examplesRef} offset={15}>
<Menu
as={Accordion}
fluid
style={sidebarStyle}
text
vertical
>
{_.map(sections, ({ examples, name }) => (
<ComponentSideBarSection
activePath={activePath}
examples={examples}
key={name}
name={name}
onItemClick={this.handleItemClick}
onTitleClick={this.handleTitleClick}
/>
))}
</Menu>
</Sticky>
)
}
}

export default ComponentSidebar
Loading