Show dropdown on hover
This commit is contained in:
committed by
Stuart Taylor
parent
09b8ff88fd
commit
3d93e70a73
@ -9,7 +9,9 @@ import {
|
||||
updateNavHeight,
|
||||
updateAppLang,
|
||||
trackEvent,
|
||||
loadCurrentChallenge
|
||||
loadCurrentChallenge,
|
||||
openDropdown,
|
||||
closeDropdown
|
||||
} from './redux/actions';
|
||||
|
||||
import { submitChallenge } from './routes/challenges/redux/actions';
|
||||
@ -25,16 +27,20 @@ const mapDispatchToProps = {
|
||||
submitChallenge,
|
||||
updateAppLang,
|
||||
trackEvent,
|
||||
loadCurrentChallenge
|
||||
loadCurrentChallenge,
|
||||
openDropdown,
|
||||
closeDropdown
|
||||
};
|
||||
|
||||
const mapStateToProps = createSelector(
|
||||
userSelector,
|
||||
state => state.app.isNavDropdownOpen,
|
||||
state => state.app.isSignInAttempted,
|
||||
state => state.app.toast,
|
||||
state => state.challengesApp.toast,
|
||||
(
|
||||
{ user: { username, points, picture } },
|
||||
isNavDropdownOpen,
|
||||
isSignInAttempted,
|
||||
toast,
|
||||
) => ({
|
||||
@ -42,6 +48,7 @@ const mapStateToProps = createSelector(
|
||||
points,
|
||||
picture,
|
||||
toast,
|
||||
isNavDropdownOpen,
|
||||
showLoading: !isSignInAttempted,
|
||||
isSignedIn: !!username
|
||||
})
|
||||
@ -62,7 +69,10 @@ const propTypes = {
|
||||
params: PropTypes.object,
|
||||
updateAppLang: PropTypes.func.isRequired,
|
||||
trackEvent: PropTypes.func.isRequired,
|
||||
loadCurrentChallenge: PropTypes.func.isRequired
|
||||
loadCurrentChallenge: PropTypes.func.isRequired,
|
||||
openDropdown: PropTypes.func.isRequired,
|
||||
closeDropdown: PropTypes.func.isRequired,
|
||||
isNavDropdownOpen: PropTypes.bool
|
||||
};
|
||||
|
||||
// export plain class for testing
|
||||
@ -102,7 +112,10 @@ export class FreeCodeCamp extends React.Component {
|
||||
picture,
|
||||
updateNavHeight,
|
||||
trackEvent,
|
||||
loadCurrentChallenge
|
||||
loadCurrentChallenge,
|
||||
openDropdown,
|
||||
closeDropdown,
|
||||
isNavDropdownOpen
|
||||
} = this.props;
|
||||
const navProps = {
|
||||
username,
|
||||
@ -110,7 +123,10 @@ export class FreeCodeCamp extends React.Component {
|
||||
picture,
|
||||
updateNavHeight,
|
||||
trackEvent,
|
||||
loadCurrentChallenge
|
||||
loadCurrentChallenge,
|
||||
openDropdown,
|
||||
closeDropdown,
|
||||
isNavDropdownOpen
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -31,14 +31,17 @@ function handleNavLinkEvent(content) {
|
||||
}
|
||||
|
||||
const propTypes = {
|
||||
points: PropTypes.number,
|
||||
closeDropdown: PropTypes.func.isRequired,
|
||||
isNavDropdownOpen: PropTypes.bool,
|
||||
loadCurrentChallenge: PropTypes.func.isRequired,
|
||||
openDropdown: PropTypes.func.isRequired,
|
||||
picture: PropTypes.string,
|
||||
signedIn: PropTypes.bool,
|
||||
username: PropTypes.string,
|
||||
updateNavHeight: PropTypes.func,
|
||||
points: PropTypes.number,
|
||||
showLoading: PropTypes.bool,
|
||||
signedIn: PropTypes.bool,
|
||||
trackEvent: PropTypes.func.isRequired,
|
||||
loadCurrentChallenge: PropTypes.func.isRequired
|
||||
updateNavHeight: PropTypes.func,
|
||||
username: PropTypes.string
|
||||
};
|
||||
|
||||
export default class FCCNav extends React.Component {
|
||||
@ -80,12 +83,23 @@ export default class FCCNav extends React.Component {
|
||||
|
||||
renderLink(isNavItem, { isReact, isDropdown, content, link, links, target }) {
|
||||
const Component = isNavItem ? NavItem : MenuItem;
|
||||
const {
|
||||
isNavDropdownOpen,
|
||||
openDropdown,
|
||||
closeDropdown
|
||||
} = this.props;
|
||||
|
||||
if (isDropdown) {
|
||||
return (
|
||||
<NavDropdown
|
||||
id={ `nav-${content}-dropdown` }
|
||||
key={ content }
|
||||
noCaret={ true }
|
||||
onClick={ openDropdown }
|
||||
onClose={ closeDropdown }
|
||||
onMouseEnter={ openDropdown }
|
||||
onMouseLeave={ closeDropdown }
|
||||
open={ isNavDropdownOpen }
|
||||
title={ content }
|
||||
>
|
||||
{ links.map(this.renderLink.bind(this, false)) }
|
||||
@ -150,17 +164,6 @@ export default class FCCNav extends React.Component {
|
||||
picture,
|
||||
showLoading
|
||||
} = this.props;
|
||||
let navLinksCache;
|
||||
|
||||
if (this._navLinksCache) {
|
||||
navLinksCache = this._navLinksCache;
|
||||
} else {
|
||||
// we cache the rendered static links on the instance
|
||||
// these do not change for the lifetime of the app
|
||||
navLinksCache = this._navLinksCache = navLinks.map(
|
||||
this.renderLink.bind(this, true)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Navbar
|
||||
@ -188,7 +191,11 @@ export default class FCCNav extends React.Component {
|
||||
navbar={ true }
|
||||
pullRight={ true }
|
||||
>
|
||||
{ navLinksCache }
|
||||
{
|
||||
navLinks.map(
|
||||
this.renderLink.bind(this, true)
|
||||
)
|
||||
}
|
||||
{ this.renderSignIn(username, points, picture, showLoading) }
|
||||
</Nav>
|
||||
</Navbar.Collapse>
|
||||
@ -197,5 +204,5 @@ export default class FCCNav extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
FCCNav.displayName = 'Nav';
|
||||
FCCNav.displayName = 'FCCNav';
|
||||
FCCNav.propTypes = propTypes;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Observable } from 'rx';
|
||||
import { createAction } from 'redux-actions';
|
||||
import types from './types';
|
||||
import noop from 'lodash/noop';
|
||||
|
||||
const throwIfUndefined = () => {
|
||||
throw new TypeError('Argument must not be of type `undefined`');
|
||||
@ -146,3 +147,6 @@ export const toggleNightMode = createAction(
|
||||
export const updateTheme = createAction(types.updateTheme);
|
||||
// addThemeToBody(theme: /night|default/) => Action
|
||||
export const addThemeToBody = createAction(types.addThemeToBody);
|
||||
|
||||
export const openDropdown = createAction(types.openDropdown, noop);
|
||||
export const closeDropdown = createAction(types.closeDropdown, noop);
|
||||
|
@ -52,6 +52,14 @@ export default handleActions(
|
||||
[types.delayedRedirect]: (state, { payload }) => ({
|
||||
...state,
|
||||
delayedRedirect: payload
|
||||
}),
|
||||
[types.openDropdown]: state => ({
|
||||
...state,
|
||||
isNavDropdownOpen: true
|
||||
}),
|
||||
[types.closeDropdown]: state => ({
|
||||
...state,
|
||||
isNavDropdownOpen: false
|
||||
})
|
||||
},
|
||||
initialState
|
||||
|
@ -1,4 +1,4 @@
|
||||
import createTypes from '../utils/create-types';
|
||||
import { createTypes } from 'redux-create-types';
|
||||
|
||||
export default createTypes([
|
||||
'analytics',
|
||||
@ -33,5 +33,9 @@ export default createTypes([
|
||||
// night mode
|
||||
'toggleNightMode',
|
||||
'updateTheme',
|
||||
'addThemeToBody'
|
||||
'addThemeToBody',
|
||||
|
||||
// nav
|
||||
'openDropdown',
|
||||
'closeDropdown'
|
||||
], 'app');
|
||||
|
@ -108,6 +108,7 @@
|
||||
"react-youtube": "^7.0.0",
|
||||
"redux": "^3.0.5",
|
||||
"redux-actions": "^0.13.0",
|
||||
"redux-create-types": "0.0.1",
|
||||
"redux-epic": "^0.1.1",
|
||||
"redux-form": "^5.2.3",
|
||||
"request": "^2.65.0",
|
||||
|
Reference in New Issue
Block a user