mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2025-03-25 20:29:45 -04:00
Merge branch 'develop' of https://github.com/LLK/scratch-www into bugfix/GH-148
# By Ray Schamp # Via Andrew Sliwinski (2) and Ray Schamp (2) * 'develop' of https://github.com/LLK/scratch-www: Fix GH-168: Rehabilitate the `Modal` props.style Fix GH-162: Show "user deletion canceled" modal Clean up activity item rendering logic Add some padding to the empty message Make sure boxes aren't transparent Add empty state for What's Happening box # Conflicts: # src/components/registration/registration.jsx
This commit is contained in:
commit
8014925cce
9 changed files with 137 additions and 70 deletions
|
@ -44,6 +44,8 @@
|
|||
"json-loader": "0.5.2",
|
||||
"json2po-stream": "1.0.3",
|
||||
"jsx-loader": "0.13.2",
|
||||
"lodash.clone": "3.0.3",
|
||||
"lodash.defaultsdeep": "3.10.0",
|
||||
"lodash.omit": "3.1.0",
|
||||
"minilog": "2.0.8",
|
||||
"node-sass": "3.3.3",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var React = require('react');
|
||||
var ReactIntl = require('react-intl');
|
||||
var defineMessages = ReactIntl.defineMessages;
|
||||
var FormattedMessage = ReactIntl.FormattedMessage;
|
||||
var FormattedRelative = ReactIntl.FormattedRelative;
|
||||
var injectIntl = ReactIntl.injectIntl;
|
||||
|
||||
|
@ -32,29 +33,46 @@ var Activity = React.createClass({
|
|||
className="activity"
|
||||
title={formatMessage(defaultMessages.whatsHappening)}>
|
||||
|
||||
<ul>
|
||||
{this.props.items.map(function (item) {
|
||||
var actorProfileUrl = '/users/' + item.actor.username + '/';
|
||||
var actionDate = new Date(item.datetime_created + 'Z');
|
||||
var activityMessageHTML = '<a href=' + actorProfileUrl + '>' +
|
||||
item.actor.username + '</a>' + item.message;
|
||||
if (item.message.replace(/\s/g, '')) {
|
||||
return (
|
||||
<li key={item.pk}>
|
||||
<a href={actorProfileUrl}>
|
||||
<img src={item.actor.thumbnail_url} width="34" height="34" />
|
||||
<p dangerouslySetInnerHTML={{__html: activityMessageHTML}}></p>
|
||||
<p>
|
||||
<span className="stamp">
|
||||
<FormattedRelative value={actionDate} />
|
||||
</span>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</ul>
|
||||
{this.props.items && this.props.items.length > 0 ? [
|
||||
<ul>
|
||||
{this.props.items.map(function (item) {
|
||||
if (item.message.replace(/\s/g, '')) {
|
||||
var actorProfileUrl = '/users/' + item.actor.username + '/';
|
||||
var actionDate = new Date(item.datetime_created + 'Z');
|
||||
var activityMessageHTML = (
|
||||
'<a href=' + actorProfileUrl + '>' + item.actor.username + '</a>' +
|
||||
item.message
|
||||
);
|
||||
return (
|
||||
<li key={item.pk}>
|
||||
<a href={actorProfileUrl}>
|
||||
<img src={item.actor.thumbnail_url} width="34" height="34" />
|
||||
<p dangerouslySetInnerHTML={{__html: activityMessageHTML}}></p>
|
||||
<p>
|
||||
<span className="stamp">
|
||||
<FormattedRelative value={actionDate} />
|
||||
</span>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</ul>
|
||||
] : [
|
||||
<div className="empty">
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="activity.seeUpdates"
|
||||
defaultMessage="This is where you will see updates from Scratchers you follow" />
|
||||
</h4>
|
||||
<a href="/studios/146521/">
|
||||
<FormattedMessage
|
||||
id="activity.checkOutScratchers"
|
||||
defaultMessage="Check out some Scratchers you might like to follow" />
|
||||
</a>
|
||||
</div>
|
||||
]}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ $base-bg: $ui-white;
|
|||
display: inline-block;
|
||||
border: 1px solid $ui-border;
|
||||
border-radius: 10px 10px 0 0;
|
||||
background-color: $ui-white;
|
||||
width: 100%;
|
||||
|
||||
.box-header {
|
||||
|
@ -44,4 +45,8 @@ $base-bg: $ui-white;
|
|||
background-color: $base-bg;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ var Intro = React.createClass({
|
|||
this.closeRegistration();
|
||||
},
|
||||
render: function () {
|
||||
var frameSettings = {
|
||||
var frameProps = {
|
||||
width: 570,
|
||||
height: 357,
|
||||
padding: 15
|
||||
|
@ -140,10 +140,10 @@ var Intro = React.createClass({
|
|||
className="video-modal"
|
||||
isOpen={this.state.videoOpen}
|
||||
onRequestClose={this.closeVideo}
|
||||
frameSettings={frameSettings}>
|
||||
style={{content:frameProps}}>
|
||||
<iframe
|
||||
src="//player.vimeo.com/video/65583694?title=0&byline=0&portrait=0"
|
||||
{...omit(frameSettings, 'padding')} />
|
||||
{...omit(frameProps, 'padding')} />
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,30 @@
|
|||
var defaults = require('lodash.defaults');
|
||||
var omit = require('lodash.omit');
|
||||
var clone = require('lodash.clone');
|
||||
var defaultsDeep = require('lodash.defaultsdeep');
|
||||
var React = require('react');
|
||||
var ReactModal = require('react-modal');
|
||||
|
||||
require('./modal.scss');
|
||||
|
||||
var defaultStyle = {
|
||||
overlay: {
|
||||
zIndex: 100,
|
||||
backgroundColor: 'rgba(0, 0, 0, .75)'
|
||||
},
|
||||
content: {
|
||||
overflow: 'visible',
|
||||
borderRadius: '6px',
|
||||
width: 500,
|
||||
height: 250,
|
||||
padding: 0,
|
||||
top: '50%',
|
||||
right: 'auto',
|
||||
bottom: 'auto',
|
||||
left: '50%',
|
||||
marginTop: -125,
|
||||
marginLeft: -250
|
||||
}
|
||||
};
|
||||
|
||||
var Modal = React.createClass({
|
||||
type: 'Modal',
|
||||
statics: {
|
||||
|
@ -12,46 +32,24 @@ var Modal = React.createClass({
|
|||
},
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
frameSettings: null,
|
||||
style: {
|
||||
overlay: {
|
||||
zIndex: 100,
|
||||
backgroundColor: 'rgba(0, 0, 0, .75)'
|
||||
},
|
||||
content: {
|
||||
overflow: 'visible',
|
||||
borderRadius: '6px'
|
||||
}
|
||||
}
|
||||
style: defaultStyle
|
||||
};
|
||||
},
|
||||
calculateStyle: function () {
|
||||
var style = clone(this.props.style, true);
|
||||
defaultsDeep(style, defaultStyle);
|
||||
style.content.marginTop = (style.content.height + style.content.padding*2) / -2;
|
||||
style.content.marginLeft = (style.content.width + style.content.padding*2) / -2;
|
||||
return style;
|
||||
},
|
||||
requestClose: function () {
|
||||
return this.refs.modal.portal.requestClose();
|
||||
},
|
||||
render: function () {
|
||||
var frameSettings = this.props.frameSettings;
|
||||
var style = this.props.style;
|
||||
var modalProps = omit(this.props, ['frameSettings', 'style']);
|
||||
if (frameSettings) {
|
||||
defaults(frameSettings, {
|
||||
width: 500,
|
||||
height: 250,
|
||||
padding: 0
|
||||
});
|
||||
defaults(style.content, {
|
||||
top: '50%',
|
||||
right: 'auto',
|
||||
bottom: 'auto',
|
||||
left: '50%',
|
||||
marginTop: (frameSettings.height + 2*frameSettings.padding) / -2,
|
||||
marginLeft: (frameSettings.width + 2*frameSettings.padding) / -2,
|
||||
height: frameSettings.height,
|
||||
width: frameSettings.width,
|
||||
padding: frameSettings.padding
|
||||
});
|
||||
}
|
||||
return (
|
||||
<ReactModal ref="modal" style={style} {...modalProps}>
|
||||
<ReactModal ref="modal"
|
||||
{...this.props}
|
||||
style={this.calculateStyle()}>
|
||||
<div className="modal-close" onClick={this.requestClose}></div>
|
||||
{this.props.children}
|
||||
</ReactModal>
|
||||
|
|
|
@ -12,11 +12,14 @@ var Dropdown = require('./dropdown.jsx');
|
|||
var Input = require('../forms/input.jsx');
|
||||
var log = require('../../lib/log.js');
|
||||
var Login = require('../login/login.jsx');
|
||||
var Modal = require('../modal/modal.jsx');
|
||||
var Registration = require('../registration/registration.jsx');
|
||||
var Session = require('../../mixins/session.jsx');
|
||||
|
||||
require('./navigation.scss');
|
||||
|
||||
Modal.setAppElement(document.getElementById('view'));
|
||||
|
||||
var defaultMessages = defineMessages({
|
||||
messages: {
|
||||
id: 'general.messages',
|
||||
|
@ -36,12 +39,13 @@ var Navigation = React.createClass({
|
|||
],
|
||||
getInitialState: function () {
|
||||
return {
|
||||
'accountNavOpen': false,
|
||||
'loginOpen': false,
|
||||
'loginError': null,
|
||||
'registrationOpen': false,
|
||||
'unreadMessageCount': 0,
|
||||
'messageCountIntervalId': -1
|
||||
accountNavOpen: false,
|
||||
canceledDeletionOpen: false,
|
||||
loginOpen: false,
|
||||
loginError: null,
|
||||
registrationOpen: false,
|
||||
unreadMessageCount: 0,
|
||||
messageCountIntervalId: -1
|
||||
};
|
||||
},
|
||||
componentDidMount: function () {
|
||||
|
@ -103,6 +107,7 @@ var Navigation = React.createClass({
|
|||
},
|
||||
handleLogIn: function (formData) {
|
||||
this.setState({'loginError': null});
|
||||
formData['useMessages'] = true;
|
||||
this.api({
|
||||
method: 'post',
|
||||
host: '',
|
||||
|
@ -119,6 +124,11 @@ var Navigation = React.createClass({
|
|||
this.setState({'loginError': body.msg});
|
||||
} else {
|
||||
this.closeLogin();
|
||||
body.messages.map(function (message) {
|
||||
if (message.message == 'canceled-deletion') {
|
||||
this.showCanceledDeletion();
|
||||
}
|
||||
}.bind(this));
|
||||
window.refreshSession();
|
||||
}
|
||||
}
|
||||
|
@ -145,6 +155,12 @@ var Navigation = React.createClass({
|
|||
closeAccountNav: function () {
|
||||
this.setState({'accountNavOpen': false});
|
||||
},
|
||||
showCanceledDeletion: function () {
|
||||
this.setState({'canceledDeletionOpen': true});
|
||||
},
|
||||
closeCanceledDeletion: function () {
|
||||
this.setState({'canceledDeletionOpen': false});
|
||||
},
|
||||
closeRegistration: function () {
|
||||
this.setState({'registrationOpen': false});
|
||||
},
|
||||
|
@ -299,6 +315,17 @@ var Navigation = React.createClass({
|
|||
</li>
|
||||
]}
|
||||
</ul>
|
||||
<Modal isOpen={this.state.canceledDeletionOpen}
|
||||
onRequestClose={this.closeCanceledDeletion}
|
||||
frameSettings={{padding: 15}}>
|
||||
<h4>Your Account Will Not Be Deleted</h4>
|
||||
<p>
|
||||
Your account was scheduled for deletion but you logged in. Your account has been reactivated.
|
||||
If you didn’t request for your account to be deleted, you should
|
||||
{' '}<a href="/accounts/password_reset/">change your password</a>{' '}
|
||||
to make sure your account is secure.
|
||||
</p>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ var Registration = React.createClass({
|
|||
this.toggleMessageListener(false);
|
||||
},
|
||||
render: function () {
|
||||
var frameSettings = {
|
||||
var frameProps = {
|
||||
width: 610,
|
||||
height: 438
|
||||
};
|
||||
|
@ -45,8 +45,8 @@ var Registration = React.createClass({
|
|||
isOpen={this.props.isOpen}
|
||||
onRequestClose={this.props.onRequestClose}
|
||||
className="registration"
|
||||
frameSettings={frameSettings}>
|
||||
<iframe ref="registrationIframe" src="/accounts/standalone-registration/" {...frameSettings} />
|
||||
style={{content:frameProps}}>
|
||||
<iframe ref="registrationIframe" src="/accounts/standalone-registration/" {...frameProps} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,21 @@ a:hover {
|
|||
width: 942px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
$bg-blue: #d9edf7;
|
||||
$bg-blue-accent: #bce8f1;
|
||||
border: 1px solid $bg-blue-accent;
|
||||
border-radius: 5px;
|
||||
background-color: $bg-blue;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
line-height: 2rem;
|
||||
color: $type-gray;
|
||||
h4 {
|
||||
color: $type-gray;
|
||||
}
|
||||
}
|
||||
|
||||
#view {
|
||||
/* NOTE: Margin should match height in navigation.scss */
|
||||
margin-top: 50px;
|
||||
|
|
|
@ -35,6 +35,8 @@ var Components = React.createClass({
|
|||
</Box>
|
||||
<h1>{'What\'s Happening??'}</h1>
|
||||
<Activity />
|
||||
<h1>{'Nothing!!!'}</h1>
|
||||
<Activity items={[]} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue