Add logged in state and dropdown

This commit is contained in:
Ray Schamp 2015-09-11 20:29:12 -04:00
parent e1d3396019
commit ab85004e4e
9 changed files with 241 additions and 98 deletions

View file

@ -3,8 +3,12 @@ var React = require('react');
require('./login.scss'); require('./login.scss');
module.exports = React.createClass({ module.exports = React.createClass({
propTypes: {
onLogIn: React.PropTypes.func
},
handleSubmit: function (event) { handleSubmit: function (event) {
event.preventDefault(); event.preventDefault();
this.props.onLogIn();
}, },
render: function () { render: function () {
return ( return (

View file

@ -1,4 +1,6 @@
.login { .login {
padding: 14px 9px;
.submit-button { .submit-button {
margin-right: 3px; margin-right: 3px;
} }

View file

@ -0,0 +1,3 @@
$base-background-color: #0f8bc0;
$active-background-color: rgb(1, 96, 135);
$border-color: rgb(20, 154, 203);

View file

@ -0,0 +1,36 @@
var React = require('react');
require('./dropdown.scss');
module.exports = React.createClass({
mixins: [
require('react-onclickoutside')
],
propTypes: {
onRequestClose: React.PropTypes.func,
isOpen: React.PropTypes.bool
},
getDefaultProps: function () {
return {
as: 'div',
isOpen: false
};
},
handleClickOutside: function () {
if (this.props.isOpen) {
this.props.onRequestClose();
}
},
render: function () {
var className = [
'dropdown',
this.props.className,
this.props.isOpen ? 'open' : ''
].join(' ');
return (
<this.props.as className={className}>
{this.props.children}
</this.props.as>
);
}
});

View file

@ -0,0 +1,74 @@
@import 'colors';
.dropdown {
position: absolute;
right: 0;
min-width: 160px;
max-width: 220px;
background-color: $base-background-color;
overflow: hidden;
border-radius: 0px 0px 4px 4px;
box-shadow: inset 0 1px 1px rgba(100,100,100,.25),0 1px 1px rgba(0,0,0,.25);
color: white;
font-weight: normal;
font-size: 0.8125rem;
display: none;
&.open {
display: block;
}
a {
color: white;
}
input {
// 100% minus border and padding
width: calc(100% - 2px - 8px);
margin-bottom: 9px;
}
label {
display: block;
margin-bottom: 5px;
}
> li {
display: block;
line-height: 30px;
&.divider {
border-top: 1px solid #149acb;
margin-top: 10px;
}
a {
display: block;
padding: 0 10px;
&:hover {
background-color: $active-background-color;
text-decoration: none;
}
}
}
&.with-arrow {
$arrow-border-width: 11px;
overflow: visible;
margin-top: $arrow-border-width;
border-radius: 4px;
&:before {
position: absolute;
display: block;
right: 10%;
top: -$arrow-border-width;
left: auto;
border-color: transparent;
border-bottom-color: $base-background-color;
border-style: solid;
border-width: 0 $arrow-border-width $arrow-border-width $arrow-border-width;
content: " ";
}
}
}

View file

@ -1,44 +1,19 @@
var React = require('react'); var React = require('react');
var Login = require('../login/login.jsx'); var Login = require('../login/login.jsx');
var Dropdown = require('./dropdown.jsx');
require('./navigation.scss'); require('./navigation.scss');
var Dropdown = React.createClass({
mixins: [
require('react-onclickoutside')
],
propTypes: {
onRequestClose: React.PropTypes.func,
isOpen: React.PropTypes.bool
},
getDefaultProps: function () {
return {
isOpen: false
};
},
handleClickOutside: function () {
if (this.props.isOpen) {
this.props.onRequestClose();
}
},
render: function () {
var className = [
'dropdown',
this.props.className,
this.props.isOpen ? 'open' : ''
].join(' ');
return (
<div className={className}>
{this.props.children}
</div>
);
}
});
module.exports = React.createClass({ module.exports = React.createClass({
getInitialState: function () { getInitialState: function () {
return { return {
'loginOpen': false 'loginOpen': false,
'loggedIn': false,
'loggedInUser': {
'username': 'raimondious',
'thumbnail': '//cdn2.scratch.mit.edu/get_image/user/2584924_32x32.png'
},
'accountNavOpen': false
}; };
}, },
handleLoginClick: function (e) { handleLoginClick: function (e) {
@ -48,9 +23,25 @@ module.exports = React.createClass({
closeLogin: function () { closeLogin: function () {
this.setState({'loginOpen': false}); this.setState({'loginOpen': false});
}, },
handleLogIn: function () {
this.setState({'loggedIn': true});
},
handleLogOut: function () {
this.setState({'loggedIn': false});
},
handleClickAccountNav: function () {
this.setState({'accountNavOpen': true});
},
closeAccountNav: function () {
this.setState({'accountNavOpen': false});
},
render: function () { render: function () {
var className = [
'inner',
this.state.loggedIn ? 'logged-in' : 'logged-out'
].join(' ');
return ( return (
<div className="inner"> <div className={className}>
<ul> <ul>
<li className="logo"><a href="/"></a></li> <li className="logo"><a href="/"></a></li>
@ -68,17 +59,38 @@ module.exports = React.createClass({
<input type="hidden" name="sort_by" value="datetime_shared" /> <input type="hidden" name="sort_by" value="datetime_shared" />
</form> </form>
</li> </li>
{this.state.loggedIn ? [
<li className="link right"><a href="/join">Join Scratch</a></li> <li className="link right messages"><a href="/messages/" title="Messages">Messages</a></li>,
<li className="link right"> <li className="link right mystuff"><a href="/mystuff/" title="My Stuff">My Stuff</a></li>,
<a href="" onClick={this.handleLoginClick}>Sign In</a> <li className="link right account-nav">
<a href="#" onClick={this.handleClickAccountNav}>
<img src={this.state.loggedInUser.thumbnail} />
{this.state.loggedInUser.username}
</a>
<Dropdown <Dropdown
className="login" as="ul"
isOpen={this.state.loginOpen} isOpen={this.state.accountNavOpen}
onRequestClose={this.closeLogin}> onRequestClose={this.closeAccountNav}>
<Login /> <li><a href="/users/raimondious/">Profile</a></li>
<li><a href="/mystuff/">My Stuff</a></li>
<li><a href="/accounts/settings/">Account settings</a></li>
<li className="divider">
<a href="#" onClick={this.handleLogOut}>Sign out</a>
</li>
</Dropdown> </Dropdown>
</li> </li>
] : [
<li className="link right join"><a href="/join">Join Scratch</a></li>,
<li className="link right">
<a href="#" onClick={this.handleLoginClick}>Sign In</a>
<Dropdown
className="login-dropdown with-arrow"
isOpen={this.state.loginOpen}
onRequestClose={this.closeLogin}>
<Login onLogIn={this.handleLogIn} />
</Dropdown>
</li>
]}
</ul> </ul>
</div> </div>
); );

View file

@ -1,5 +1,4 @@
$base-background-color: #0f8bc0; @import 'colors';
$border-color: rgb(20, 154, 203);
#navigation { #navigation {
position: fixed; position: fixed;
@ -13,7 +12,7 @@ $border-color: rgb(20, 154, 203);
/* NOTE: Height should match offset settings in main.scss file */ /* NOTE: Height should match offset settings in main.scss file */
height: 35px; height: 35px;
ul { .inner > ul {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -24,7 +23,7 @@ $border-color: rgb(20, 154, 203);
padding: 0; padding: 0;
list-style: none; list-style: none;
li { > li {
display: inline-block; display: inline-block;
align-self: flex-start; align-self: flex-start;
float: left; float: left;
@ -65,7 +64,7 @@ $border-color: rgb(20, 154, 203);
} }
> a:hover { > a:hover {
background-color: rgb(1, 96, 135); background-color: $active-background-color;
} }
} }
@ -115,64 +114,77 @@ $border-color: rgb(20, 154, 203);
margin-left: auto; margin-left: auto;
font-weight: bold; font-weight: bold;
> a:hover {
background-color: #f79231;
}
&:last-child { &:last-child {
border-right: 1px solid rgb(20, 154, 203); border-right: 1px solid rgb(20, 154, 203);
} }
} }
.dropdown { .join > a:hover {
$dropdown-padding-h: 14px; background-color: #f79231;
$dropdown-padding-v: 9px; }
position: absolute;
right: 0; .messages, .mystuff {
> a {
background-repeat: no-repeat;
background-position: center center;
padding-left: 10px;
padding-right: 10px;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}
}
.messages {
> a {
background-image: url('/images/nav-notifications.png');
width: 22px;
}
}
.mystuff {
> a {
background-image: url('/images/mystuff.png');
width: 25px;
}
}
.login-dropdown {
width: 200px; width: 200px;
padding: $dropdown-padding-v $dropdown-padding-h; }
background-color: $base-background-color;
border-radius: 4px; .account-nav {
box-shadow: 0 2px 4px rgba(0,0,0,0.2); > a {
color: white;
font-weight: normal; font-weight: normal;
font-size: 0.8125rem; font-size: 0.8125rem;
display: none; img {
&.open { width: 24px;
display: block; height: 24px;
margin-right: 5px;
vertical-align: middle;
} }
$arrow-border-width: 11px; &:after {
margin-top: $arrow-border-width; $caret-border-width: 4px;
&:before { margin-left: $caret-border-width;
position: absolute; border: $caret-border-width solid transparent;
display: block; border-bottom-width: 0;
right: 10%; border-top-color: white;
top: -$arrow-border-width;
left: auto;
border-color: transparent;
border-bottom-color: $base-background-color;
border-style: solid;
border-width: 0 $arrow-border-width $arrow-border-width $arrow-border-width;
content: " "; content: " ";
opacity: 0.5;
vertical-align: middle;
width: 0;
height: 0;
display: inline-block;
}
} }
a { .dropdown {
color: white; width: 100%;
padding: 0;
padding-top: 5px;
} }
input {
// 100% minus border and padding
width: calc(100% - 2px - 8px);
margin-bottom: 9px;
}
label {
display: block;
margin-bottom: 5px;
}
} }
} }
} }

BIN
static/images/mystuff.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB