fix(git): Merge temp branch to fix/binButtons

This commit is contained in:
Stuart Taylor
2018-03-13 20:17:13 +00:00
14 changed files with 333 additions and 109 deletions

View File

@ -328,7 +328,7 @@
@grid-gutter-width: 30px; @grid-gutter-width: 30px;
// Navbar collapse // Navbar collapse
//** Point at which the navbar becomes uncollapsed. //** Point at which the navbar becomes uncollapsed.
@grid-float-breakpoint: @screen-sm-min; @grid-float-breakpoint: 955px;
//** Point at which the navbar begins collapsing. //** Point at which the navbar begins collapsing.
@grid-float-breakpoint-max: (@grid-float-breakpoint - 1); @grid-float-breakpoint-max: (@grid-float-breakpoint - 1);

View File

@ -0,0 +1,47 @@
import React from 'react';
import Media from 'react-media';
import { Col, Navbar, Row } from 'react-bootstrap';
import FCCSearchBar from 'react-freecodecamp-search';
import { NavLogo, BinButtons, NavLinks } from './components';
import propTypes from './navPropTypes';
function LargeNav({ clickOnLogo, clickOnMap, shouldShowMapButton, panes }) {
return (
<Media
query='(min-width: 956px)'
render={
() => (
<Row>
<Col className='nav-component' sm={ 4 } xs={ 6 }>
<Navbar.Header>
<NavLogo clickOnLogo={ clickOnLogo } />
<FCCSearchBar
dropdown={ true }
placeholder=
'&#xf002; Search 8,000+ lessons, articles, and videos'
/>
</Navbar.Header>
</Col>
<Col className='nav-component bins' sm={ 4 } xs={ 6 }>
<BinButtons panes={ panes } />
</Col>
<Col className='nav-component nav-links' sm={ 4 } xs={ 0 }>
<Navbar.Collapse>
<NavLinks
clickOnMap={ clickOnMap }
shouldShowMapButton={ shouldShowMapButton }
/>
</Navbar.Collapse>
</Col>
</Row>
)
}
/>
);
}
LargeNav.displayName = 'LargeNav';
LargeNav.propTypes = propTypes;
export default LargeNav;

View File

@ -0,0 +1,52 @@
import React from 'react';
import Media from 'react-media';
import { Col, Navbar, Row } from 'react-bootstrap';
import FCCSearchBar from 'react-freecodecamp-search';
import { NavLogo, BinButtons, NavLinks } from './components';
import propTypes from './navPropTypes';
function MediumNav({ clickOnLogo, clickOnMap, shouldShowMapButton, panes }) {
return (
<Media
query={{ maxWidth: 955, minWidth: 751 }}
render={
() => (
<div>
<Row>
<Navbar.Header className='medium-nav'>
<div className='nav-component header'>
<Navbar.Toggle />
<NavLogo clickOnLogo={ clickOnLogo } />
<FCCSearchBar
dropdown={ true }
placeholder=
'&#xf002; Search 8,000+ lessons, articles, and videos'
/>
</div>
<div className='nav-component bins'>
<BinButtons panes={ panes } />
</div>
</Navbar.Header>
</Row>
<Row>
<Col xs={ 12 }>
<Navbar.Collapse>
<NavLinks
clickOnMap={ clickOnMap }
shouldShowMapButton={ shouldShowMapButton }
/>
</Navbar.Collapse>
</Col>
</Row>
</div>
)
}
/>
);
}
MediumNav.displayName = 'MediumNav';
MediumNav.propTypes = propTypes;
export default MediumNav;

View File

@ -1,19 +1,18 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import FCCSearchBar from 'react-freecodecamp-search'; import { Navbar } from 'react-bootstrap';
import {
Navbar
} from 'react-bootstrap';
import { BinButtons, NavLogo, NavLinks } from './components'; import LargeNav from './LargeNav.jsx';
import MediumNav from './MediumNav.jsx';
import SmallNav from './SmallNav.jsx';
import { import {
clickOnLogo, clickOnLogo,
clickOnMap clickOnMap
} from './redux'; } from './redux';
import { panesSelector } from '../Panes/redux'; import { panesSelector } from '../Panes/redux';
import propTypes from './navPropTypes';
const mapStateToProps = createSelector( const mapStateToProps = createSelector(
panesSelector, panesSelector,
@ -63,13 +62,6 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
}; };
} }
const propTypes = {
clickOnLogo: PropTypes.func.isRequired,
clickOnMap: PropTypes.func.isRequired,
panes: PropTypes.array,
shouldShowMapButton: PropTypes.bool
};
function FCCNav(props) { function FCCNav(props) {
const { const {
panes, panes,
@ -83,23 +75,24 @@ function FCCNav(props) {
id='navbar' id='navbar'
staticTop={ true } staticTop={ true }
> >
<div className='nav-component-wrapper'> <LargeNav
<Navbar.Header> clickOnLogo={ clickOnLogo }
<Navbar.Toggle children={ 'Menu' } /> clickOnMap={ clickOnMap }
<NavLogo clickOnLogo={ clickOnLogo } /> panes={ panes }
<FCCSearchBar shouldShowMapButton={ shouldShowMapButton }
dropdown={ true } />
placeholder='&#xf002; Search 8,000+ lessons, articles, and videos' <MediumNav
/> clickOnLogo={ clickOnLogo }
</Navbar.Header> clickOnMap={ clickOnMap }
<BinButtons panes={ panes } /> panes={ panes }
<Navbar.Collapse> shouldShowMapButton={ shouldShowMapButton }
<NavLinks />
clickOnMap={ clickOnMap } <SmallNav
shouldShowMapButton={ shouldShowMapButton } clickOnLogo={ clickOnLogo }
/> clickOnMap={ clickOnMap }
</Navbar.Collapse> panes={ panes }
</div> shouldShowMapButton={ shouldShowMapButton }
/>
</Navbar> </Navbar>
); );
} }

View File

@ -0,0 +1,53 @@
import React from 'react';
import Media from 'react-media';
import { Col, Navbar, Row } from 'react-bootstrap';
import FCCSearchBar from 'react-freecodecamp-search';
import { NavLogo, BinButtons, NavLinks } from './components';
import propTypes from './navPropTypes';
function SmallNav({ clickOnLogo, clickOnMap, shouldShowMapButton, panes }) {
return (
<Media
query='(max-width: 750px)'
render={
() => (
<div>
<Row>
<Navbar.Header className='small-nav'>
<div className='nav-component header'>
<Navbar.Toggle />
<NavLogo clickOnLogo={ clickOnLogo } />
</div>
<div className='nav-component bins'>
<BinButtons panes={ panes } />
</div>
</Navbar.Header>
</Row>
<Row>
<Col xs={ 12 }>
<Navbar.Collapse>
<NavLinks
clickOnMap={ clickOnMap }
shouldShowMapButton={ shouldShowMapButton }
>
<FCCSearchBar
dropdown={ true }
placeholder=
'&#xf002; Search 8,000+ lessons, articles, and videos'
/>
</NavLinks>
</Navbar.Collapse>
</Col>
</Row>
</div>
)
}
/>
);
}
SmallNav.displayName = 'SmallNav';
SmallNav.propTypes = propTypes;
export default SmallNav;

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { NavItem } from 'react-bootstrap'; import { Button } from 'react-bootstrap';
const propTypes = { const propTypes = {
content: PropTypes.string, content: PropTypes.string,
@ -9,11 +9,12 @@ const propTypes = {
export default function BinButton({ content, handleClick }) { export default function BinButton({ content, handleClick }) {
return ( return (
<NavItem <Button
bsStyle='primary'
onClick={ handleClick } onClick={ handleClick }
> >
{ content } { content }
</NavItem> </Button>
); );
} }
BinButton.displayName = 'BinButton'; BinButton.displayName = 'BinButton';

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Nav } from 'react-bootstrap'; import { ButtonGroup } from 'react-bootstrap';
import BinButton from './Bin-Button.jsx'; import BinButton from './Bin-Button.jsx';
const propTypes = { const propTypes = {
@ -14,19 +14,17 @@ const propTypes = {
function BinButtons({ panes }) { function BinButtons({ panes }) {
return ( return (
<div id='bin-buttons'> <ButtonGroup>
<Nav> {
{ panes.map(({ content, actionCreator }) => (
panes.map(({ content, actionCreator }) => ( <BinButton
<BinButton content={ content }
content={ content } handleClick={ actionCreator }
handleClick={ actionCreator } key={ content }
key={ content } />
/> ))
)) }
} </ButtonGroup>
</Nav>
</div>
); );
} }

View File

@ -57,9 +57,11 @@ const navLinkPropType = PropTypes.shape({
}); });
const propTypes = { const propTypes = {
children: PropTypes.any,
clickOnMap: PropTypes.func.isRequired, clickOnMap: PropTypes.func.isRequired,
closeDropdown: PropTypes.func.isRequired, closeDropdown: PropTypes.func.isRequired,
isDropdownOpen: PropTypes.bool, isDropdownOpen: PropTypes.bool,
isInNav: PropTypes.bool,
isSignedIn: PropTypes.bool, isSignedIn: PropTypes.bool,
navLinks: PropTypes.arrayOf(navLinkPropType), navLinks: PropTypes.arrayOf(navLinkPropType),
openDropdown: PropTypes.func.isRequired, openDropdown: PropTypes.func.isRequired,
@ -86,8 +88,6 @@ class NavLinks extends PureComponent {
key={ content } key={ content }
noCaret={ true } noCaret={ true }
onClick={ openDropdown } onClick={ openDropdown }
onMouseEnter={ openDropdown }
onMouseLeave={ closeDropdown }
onToggle={ isDropdownOpen ? closeDropdown : openDropdown } onToggle={ isDropdownOpen ? closeDropdown : openDropdown }
open={ isDropdownOpen } open={ isDropdownOpen }
title={ content } title={ content }
@ -129,10 +129,13 @@ class NavLinks extends PureComponent {
clickOnMap, clickOnMap,
showLoading, showLoading,
isSignedIn, isSignedIn,
navLinks navLinks,
isInNav = true,
children
} = this.props; } = this.props;
return ( return (
<Nav id='nav-links' navbar={ true } pullRight={ true }> <Nav id='nav-links' navbar={ true } pullRight={ true }>
{ children }
{ {
shouldShowMapButton ? shouldShowMapButton ?
<NoPropsPassThrough> <NoPropsPassThrough>
@ -149,10 +152,11 @@ class NavLinks extends PureComponent {
} }
{ {
navLinks.map( navLinks.map(
this.renderLink.bind(this, true) this.renderLink.bind(this, isInNav)
) )
} }
<SignUp <SignUp
isInDropDown={ !isInNav }
showLoading={ showLoading } showLoading={ showLoading }
showSignUp={ !isSignedIn } showSignUp={ !isSignedIn }
/> />

View File

@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { NavbarBrand } from 'react-bootstrap'; import { NavbarBrand } from 'react-bootstrap';
import Media from 'react-media';
const fCClogo = 'https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg'; const fCClogo = 'https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg';
// TODO @freecodecamp-team: place this glyph in S3 like above, PR in /assets // TODO @freecodecamp-team: place this glyph in S3 like above, PR in /assets
const fCCglyph = 'https://raw.githubusercontent.com/freeCodeCamp/assets/' + const fCCglyph = 'https://raw.githubusercontent.com/freeCodeCamp/assets/' +
'3b9cafc312802199ebba8b31fb1ed9b466a3efbb/assets/logos/FFCFire.png'; '3b9cafc312802199ebba8b31fb1ed9b466a3efbb/assets/logos/FFCFire.png';
const propTypes = { const propTypes = {
clickOnLogo: PropTypes.func.isRequired clickOnLogo: PropTypes.func.isRequired
@ -18,16 +19,23 @@ function NavLogo({ clickOnLogo }) {
href='/challenges/current-challenge' href='/challenges/current-challenge'
onClick={ clickOnLogo } onClick={ clickOnLogo }
> >
<img <Media query='(min-width: 735px)'>
alt='learn to code javascript at freeCodeCamp logo' {
className='img-responsive nav-logo logo' matches => matches ? (
src={ fCClogo } <img
/> alt='learn to code javascript at freeCodeCamp logo'
<img className='nav-logo logo'
alt='learn to code javascript at freeCodeCamp logo' src={ fCClogo }
className='img-responsive logo-glyph' />
src={ fCCglyph } ) : (
/> <img
alt='learn to code javascript at freeCodeCamp logo'
className='nav-logo logo'
src={ fCCglyph }
/>
)
}
</Media>
</a> </a>
</NavbarBrand> </NavbarBrand>
); );

View File

@ -1,21 +1,29 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { NavItem } from 'react-bootstrap'; import { MenuItem, NavItem } from 'react-bootstrap';
import { Link } from '../../Router'; import { Link } from '../../Router';
import { onRouteSettings } from '../../routes/Settings/redux'; import { onRouteSettings } from '../../routes/Settings/redux';
const propTypes = { const propTypes = {
isInDropDown: PropTypes.bool,
showLoading: PropTypes.bool, showLoading: PropTypes.bool,
showSignUp: PropTypes.bool showSignUp: PropTypes.bool
}; };
export default function SignUpButton({ showLoading, showSignUp }) { function SignUpButton({ isInDropDown, showLoading, showSignUp }) {
if (showLoading) { if (showLoading) {
return null; return null;
} }
if (showSignUp) { if (showSignUp) {
return ( return isInDropDown ? (
<MenuItem
href='/signup'
key='signup'
>
Sign Up
</MenuItem>
) : (
<NavItem <NavItem
href='/signup' href='/signup'
key='signup' key='signup'
@ -38,3 +46,5 @@ export default function SignUpButton({ showLoading, showSignUp }) {
SignUpButton.displayName = 'SignUpButton'; SignUpButton.displayName = 'SignUpButton';
SignUpButton.propTypes = propTypes; SignUpButton.propTypes = propTypes;
export default SignUpButton;

View File

@ -223,64 +223,90 @@ li.nav-avatar {
} }
} }
.nav-component-wrapper { .nav-component {
display: flex; display: flex;
justify-content: space-evenly;
align-items: center; align-items: center;
&.header{
.navbar-brand {
padding-left: 0px;
}
}
&.bins {
justify-content: center;
.nav {
display: flex;
}
}
&.nav-links {
justify-content: end;
}
.fcc_searchBar { .fcc_searchBar {
width: auto; width: auto;
flex-grow: 1
}
::-webkit-input-placeholder {
color: @input-color-placeholder;
}
::-moz-placeholder {
color: @input-color-placeholder;
}
::-ms-placeholder {
color: @input-color-placeholder;
}
::placeholder {
color: @input-color-placeholder;
}
.navbar-header {
flex-grow: 1; flex-grow: 1;
::-webkit-input-placeholder {
color: @input-color-placeholder;
}
::-moz-placeholder {
color: @input-color-placeholder;
}
::-ms-placeholder {
color: @input-color-placeholder;
}
::placeholder {
color: @input-color-placeholder;
}
}
.navbar-header {
display: flex; display: flex;
align-items: center; align-items: center;
margin-right: 10px; width: 100%;
} }
} }
.logo-glyph { .medium-nav {
height: 28px; display: flex;
width: auto; justify-content: space-between;
}
.logo { .bins {
display: none !important; justify-content: flex-end;
}
@media (min-width: 992px) {
.logo-glyph {
display: none !important;
} }
}
.small-nav {
display: flex;
justify-content: space-between;
.bins {
justify-content: flex-end;
.btn {
padding: 6px 4px;
}
}
}
.bins {
.btn {
border-color: @brand-primary;
background-color: white;
&:hover {
background-color: @brand-primary;
}
.logo {
display: block !important;
}
}
@media screen and (max-width: 768px) {
.nav-component-wrapper {
display: block
} }
} }

View File

@ -0,0 +1,8 @@
import PropTypes from 'prop-types';
export default {
clickOnLogo: PropTypes.func.isRequired,
clickOnMap: PropTypes.func.isRequired,
panes: PropTypes.array,
shouldShowMapButton: PropTypes.bool
};

23
package-lock.json generated
View File

@ -9231,6 +9231,14 @@
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
}, },
"json2mq": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
"integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=",
"requires": {
"string-convert": "0.2.1"
}
},
"json3": { "json3": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
@ -14079,6 +14087,16 @@
"deep-equal": "1.0.1" "deep-equal": "1.0.1"
} }
}, },
"react-media": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/react-media/-/react-media-1.8.0.tgz",
"integrity": "sha512-XcfqkDQj5/hmJod/kXUAZljJyMVkWrBWOkzwynAR8BXOGlbFLGBwezM0jQHtp2BrSymhf14/XrQrb3gGBnGK4g==",
"requires": {
"invariant": "2.2.2",
"json2mq": "0.2.0",
"prop-types": "15.6.0"
}
},
"react-motion": { "react-motion": {
"version": "0.4.8", "version": "0.4.8",
"resolved": "https://registry.npmjs.org/react-motion/-/react-motion-0.4.8.tgz", "resolved": "https://registry.npmjs.org/react-motion/-/react-motion-0.4.8.tgz",
@ -16293,6 +16311,11 @@
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
}, },
"string-convert": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
"integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c="
},
"string-length": { "string-length": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz",

View File

@ -119,6 +119,7 @@
"react-freecodecamp-search": "^1.4.1", "react-freecodecamp-search": "^1.4.1",
"react-helmet": "^5.2.0", "react-helmet": "^5.2.0",
"react-images": "^0.5.1", "react-images": "^0.5.1",
"react-media": "^1.8.0",
"react-motion": "~0.4.2", "react-motion": "~0.4.2",
"react-no-ssr": "^1.0.1", "react-no-ssr": "^1.0.1",
"react-notification": "git+https://github.com/BerkeleyTrue/react-notification.git#freecodecamp", "react-notification": "git+https://github.com/BerkeleyTrue/react-notification.git#freecodecamp",