mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-26 17:16:11 -05:00
Add logged in state and dropdown
This commit is contained in:
parent
e1d3396019
commit
ab85004e4e
9 changed files with 241 additions and 98 deletions
|
@ -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 (
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
.login {
|
.login {
|
||||||
|
padding: 14px 9px;
|
||||||
|
|
||||||
.submit-button {
|
.submit-button {
|
||||||
margin-right: 3px;
|
margin-right: 3px;
|
||||||
}
|
}
|
||||||
|
|
3
src/components/navigation/_colors.scss
Normal file
3
src/components/navigation/_colors.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
$base-background-color: #0f8bc0;
|
||||||
|
$active-background-color: rgb(1, 96, 135);
|
||||||
|
$border-color: rgb(20, 154, 203);
|
36
src/components/navigation/dropdown.jsx
Normal file
36
src/components/navigation/dropdown.jsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
74
src/components/navigation/dropdown.scss
Normal file
74
src/components/navigation/dropdown.scss
Normal 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: " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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
BIN
static/images/mystuff.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 431 B |
BIN
static/images/nav-notifications.png
Normal file
BIN
static/images/nav-notifications.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Loading…
Reference in a new issue