Skip to content

Commit

Permalink
🎨 Re-usable dropdown component, 👏 Close dropdown when click outside, …
Browse files Browse the repository at this point in the history
…actually open creator / community profile
  • Loading branch information
fasterthanlime committed Mar 21, 2016
1 parent b1cb247 commit c6e7f84
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 33 deletions.
76 changes: 76 additions & 0 deletions appsrc/components/dropdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@

import React, {Component, PropTypes} from 'react'
import classNames from 'classnames'

import Icon from './icon'
import {map} from 'underline'

import listensToClickOutside from 'react-onclickoutside/decorator'
import {connect} from './connect'

export class Dropdown extends Component {

constructor () {
super()
this.state = {open: false}
}

render () {
const {t, items, inner, className = ''} = this.props

const {open} = this.state
const dropdownClasses = classNames('dropdown', {active: open})

const children = items::map((item) => {
const {label, icon, onClick} = item

return <section key={label + '-' + icon} onClick={onClick}>
<Icon icon={icon}/>
{t.apply(null, label)}
</section>
})

return <div style={{position: 'relative'}} className={className}>
<div onClick={this.toggle.bind(this)}>{inner}</div>
<div className='dropdown-container'>
<div className={dropdownClasses}>
{children}
</div>
</div>
</div>
}

toggle () {
this.setState({...this.state, open: !this.state.open})
}

close () {
this.setState({...this.state, open: false})
}

handleClickOutside () {
this.close()
}

}

Dropdown.propTypes = {
inner: PropTypes.element,
className: PropTypes.string,
items: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.array.isRequired,
icon: PropTypes.string
})),

t: PropTypes.func.isRequired
}

const listening = listensToClickOutside(Dropdown)

const mapStateToProps = (state) => ({})
const mapDispatchToProps = (dispatch) => ({})

export default connect(
mapStateToProps,
mapDispatchToProps
)(listening)
52 changes: 23 additions & 29 deletions appsrc/components/hub-sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,12 @@ import * as actions from '../actions'
import defaultImages from '../constants/default-images'

import Icon from './icon'
import Dropdown from './dropdown'

export class HubSidebar extends Component {

constructor () {
super()
this.state = {
dropdownOpen: false
}
}

toggleDropdown () {
const {dropdownOpen} = this.state
this.setState({...this.state, dropdownOpen: !dropdownOpen})
}

render () {
Expand All @@ -28,7 +22,6 @@ export class HubSidebar extends Component {

return <div className={classes}>
<div className='title-bar-padder'/>
{this.me()}
{this.dropdown()}

<h2>Constant</h2>
Expand Down Expand Up @@ -94,7 +87,7 @@ export class HubSidebar extends Component {
const {me = {}} = this.props
const {coverUrl = defaultImages.avatar, username = ''} = me

return <section className='me' onClick={() => this.toggleDropdown()}>
return <section className='me'>
<img src={coverUrl}/>
<span>{username}</span>
<div className='filler'/>
Expand All @@ -103,25 +96,26 @@ export class HubSidebar extends Component {
}

dropdown () {
const {t, viewCreatorProfile, viewCommunityProfile, changeUser} = this.props
const dropdownClasses = classNames('dropdown', {active: this.state.dropdownOpen})

return <div className='dropdown-container'>
<div className={dropdownClasses}>
<section onClick={viewCreatorProfile}>
<span className='icon icon-rocket'/>
{t('sidebar.view_creator_profile')}
</section>
<section onClick={viewCommunityProfile}>
<span className='icon icon-fire'/>
{t('sidebar.view_community_profile')}
</section>
<section onClick={changeUser}>
<span className='icon icon-exit'/>
{t('sidebar.log_out')}
</section>
</div>
</div>
const {viewCreatorProfile, viewCommunityProfile, changeUser} = this.props

const items = [
{
icon: 'rocket',
label: ['sidebar.view_creator_profile'],
onClick: viewCreatorProfile
},
{
icon: 'fire',
label: ['sidebar.view_community_profile'],
onClick: viewCommunityProfile
},
{
icon: 'exit',
label: ['sidebar.log_out'],
onClick: changeUser
}
]
return <Dropdown items={items} inner={this.me()}/>
}
}

Expand Down
2 changes: 1 addition & 1 deletion appsrc/components/status-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class StatusBar extends Component {
}

StatusBar.propTypes = {
offlineMode: false,
offlineMode: PropTypes.bool,
selfUpdate: PropTypes.shape({
status: PropTypes.string,
error: PropTypes.string,
Expand Down
23 changes: 20 additions & 3 deletions appsrc/sagas/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import {takeEvery} from 'redux-saga'
import {call, select, put} from 'redux-saga/effects'
import {pluck} from 'underline'

import {navigate} from '../actions'
import {SHOW_PREVIOUS_TAB, SHOW_NEXT_TAB, OPEN_URL} from '../constants/action-types'
import urls from '../constants/urls'

import {navigate, openUrl} from '../actions'
import {
SHOW_PREVIOUS_TAB, SHOW_NEXT_TAB, OPEN_URL,
VIEW_CREATOR_PROFILE, VIEW_COMMUNITY_PROFILE
} from '../constants/action-types'

export function * applyTabOffset (offset) {
const {path, tabs} = yield select((state) => state.session.navigation)
Expand Down Expand Up @@ -36,10 +41,22 @@ export function * _openUrl (action) {
yield call([shell, shell.openExternal], uri)
}

export function * _viewCreatorProfile (action) {
const url = yield select((state) => state.session.credentials.me.url)
yield put(openUrl(url))
}

export function * _viewCommunityProfile (action) {
const username = yield select((state) => state.session.credentials.me.username)
yield put(openUrl(`${urls.itchio}/profile/${username}`))
}

export default function * navigationSaga () {
yield [
takeEvery(SHOW_PREVIOUS_TAB, _showPreviousTab),
takeEvery(SHOW_NEXT_TAB, _showNextTab),
takeEvery(OPEN_URL, _openUrl)
takeEvery(OPEN_URL, _openUrl),
takeEvery(VIEW_CREATOR_PROFILE, _viewCreatorProfile),
takeEvery(VIEW_COMMUNITY_PROFILE, _viewCommunityProfile)
]
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"react": "^0.14.6",
"react-dom": "^0.14.6",
"react-modal": "^0.6.1",
"react-onclickoutside": "^4.5.0",
"react-redux": "^4.4.1",
"react-timeago": "^2.2.1",
"read-chunk": "^1.0.1",
Expand Down

0 comments on commit c6e7f84

Please sign in to comment.