import PropTypes from 'prop-types'; import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { withRouter } from 'react-router'; import { Link } from 'react-router'; import InlineSVG from 'react-inlinesvg'; import classNames from 'classnames'; import * as IDEActions from '../modules/IDE/actions/ide'; import { metaKeyName, } from '../utils/metaKey'; const triangleUrl = require('../images/down-filled-triangle.svg'); const logoUrl = require('../images/p5js-logo-small.svg'); class Nav extends React.PureComponent { constructor(props) { super(props); this.state = { dropdownOpen: 'none' }; this.handleFocus = this.handleFocus.bind(this); this.handleBlur = this.handleBlur.bind(this); this.clearHideTimeout = this.clearHideTimeout.bind(this); this.handleClick = this.handleClick.bind(this); this.handleClickOutside = this.handleClickOutside.bind(this); } componentWillMount() { document.addEventListener('mousedown', this.handleClick, false); } componentWillUnmount() { document.removeEventListener('mousedown', this.handleClick, false); } setDropdown(dropdown) { this.setState({ dropdownOpen: dropdown }); } handleClick(e) { if (this.node.contains(e.target)) { return; } this.handleClickOutside(); } handleClickOutside() { this.setState({ dropdownOpen: 'none' }); } toggleDropdown(dropdown) { if (this.state.dropdownOpen === 'none') { this.setState({ dropdownOpen: dropdown }); } else { this.setState({ dropdownOpen: 'none' }); } } isUserOwner() { return this.props.project.owner && this.props.project.owner.id === this.props.user.id; } handleFocus(dropdown) { this.clearHideTimeout(); this.setDropdown(dropdown); } clearHideTimeout() { if (this.timer) { clearTimeout(this.timer); this.timer = null; } } handleBlur() { this.timer = setTimeout(this.setDropdown.bind(this, 'none'), 10); } render() { const navDropdownState = { file: classNames({ 'nav__item': true, 'nav__item--open': this.state.dropdownOpen === 'file' }), edit: classNames({ 'nav__item': true, 'nav__item--open': this.state.dropdownOpen === 'edit' }), sketch: classNames({ 'nav__item': true, 'nav__item--open': this.state.dropdownOpen === 'sketch' }), help: classNames({ 'nav__item': true, 'nav__item--open': this.state.dropdownOpen === 'help' }), account: classNames({ 'nav__item': true, 'nav__item--open': this.state.dropdownOpen === 'account' }) }; return ( ); } } Nav.propTypes = { newProject: PropTypes.func.isRequired, saveProject: PropTypes.func.isRequired, autosaveProject: PropTypes.func.isRequired, exportProjectAsZip: PropTypes.func.isRequired, cloneProject: PropTypes.func.isRequired, user: PropTypes.shape({ authenticated: PropTypes.bool.isRequired, username: PropTypes.string, id: PropTypes.string }).isRequired, project: PropTypes.shape({ id: PropTypes.string, owner: PropTypes.shape({ id: PropTypes.string }) }), logoutUser: PropTypes.func.isRequired, showShareModal: PropTypes.func.isRequired, showErrorModal: PropTypes.func.isRequired, unsavedChanges: PropTypes.bool.isRequired, warnIfUnsavedChanges: PropTypes.func.isRequired, showKeyboardShortcutModal: PropTypes.func.isRequired, cmController: PropTypes.shape({ tidyCode: PropTypes.func, showFind: PropTypes.func, findNext: PropTypes.func, findPrev: PropTypes.func }), startSketch: PropTypes.func.isRequired, stopSketch: PropTypes.func.isRequired, setAllAccessibleOutput: PropTypes.func.isRequired, newFile: PropTypes.func.isRequired, newFolder: PropTypes.func.isRequired }; Nav.defaultProps = { project: { id: undefined, owner: undefined }, cmController: {} }; function mapDispatchToProps(dispatch) { return bindActionCreators( Object.assign( {}, IDEActions ), dispatch ); } export default withRouter(connect(() => ({}), mapDispatchToProps)(Nav));