Unverified Commit 1326f71a authored by picklesrus's avatar picklesrus Committed by GitHub

Merge branch 'develop' into timeout-mute

parents 55d69b0e bbef2eef
This diff is collapsed.
......@@ -11,10 +11,11 @@
}
.mute-step {
display: flex;
padding: 48px 16px;
padding: 36px 16px 28px 16px;
}
.mute-content {
padding-top: 16px;
justify-content: flex-start;
}
.mute-inner-content {
padding: 0 32px;
......@@ -29,7 +30,7 @@
line-height: 2rem;
}
.mute-bottom-row {
padding-top: 32px;
padding-top: 12px;
}
.bottom-img {
width: 380px;
......@@ -47,7 +48,7 @@
.mute-nav {
display:flex;
justify-content: space-between;
padding: 24px 0;
padding: 20px 0;
}
.back-button {
margin-top: 0;
......
......@@ -13,7 +13,11 @@ const PeopleGrid = props => (
>
<div>
{person.userName ? (
<a href={`https://scratch.mit.edu/users/${person.userName}/`}>
<a
href={`https://scratch.mit.edu/users/${person.userName}/`}
rel="noreferrer noopener"
target={props.linkToNewTab ? '_blank' : '_self'}
>
<Avatar
alt=""
src={`https://cdn.scratch.mit.edu/get_image/user/${person.userId || 'default'}_80x80.png`}
......@@ -36,6 +40,7 @@ const PeopleGrid = props => (
);
PeopleGrid.propTypes = {
linkToNewTab: PropTypes.bool,
people: PropTypes.arrayOf(PropTypes.shape({
name: PropTypes.string,
userId: PropTypes.number,
......@@ -43,4 +48,8 @@ PeopleGrid.propTypes = {
}))
};
PeopleGrid.defaultProps = {
linkToNewTab: false
};
module.exports = PeopleGrid;
......@@ -20,10 +20,7 @@ const WorldMap = props => (
locations: props.countryNames,
z: props.colorIndex,
text: props.countryData,
hovertemplate: '<b> %{location} </b>' +
'<br>' +
' %{text:,.0f} ' +
'<extra></extra>',
hovertemplate: '%{text}<extra></extra>',
hoverlabel: {
bgcolor: '#FFF',
bordercolor: '#5B6671',
......@@ -38,7 +35,7 @@ const WorldMap = props => (
marker: {
line: {
color: '#FFFF',
width: 1
width: .4
}
}
}
......
......@@ -53,6 +53,9 @@
</head>
<body>
<noscript>
<p>Your browser has Javascript disabled. Please go to your browser preferences and enable Javascript in order to use Scratch.</p>
</noscript>
<div id="app"></div>
<!-- Vendor & Initialize (Session & Localization)-->
......
......@@ -2,7 +2,6 @@ const bindAll = require('lodash.bindall');
const classNames = require('classnames');
const React = require('react');
const MediaQuery = require('react-responsive').default;
const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage;
const FormattedMessage = require('react-intl').FormattedMessage;
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
......@@ -52,10 +51,11 @@ const SECTION_NAMES = {
};
// Constants used for world map data processing/formatting for use with Plotly
const countryKeys = Object.keys(CountryUsage);
const countryNames = countryKeys.map(key => CountryUsage[key].display);
const countryData = countryKeys.map(key => CountryUsage[key].count);
const colorIndex = countryKeys.map(key => CountryUsage[key]['log count']);
const countryNames = Object.keys(CountryUsage);
const countryData = countryNames.map(key =>
`<b>${CountryUsage[key].display}</b><br>${CountryUsage[key].count.toLocaleString('en')}`
);
const colorIndex = countryNames.map(key => CountryUsage[key]['log count']);
// Create the div given a list of supporter names,
// this will contain two columns of names either of equal size
......@@ -1993,11 +1993,11 @@ class AnnualReport extends React.Component {
<FormattedMessage id="annualReport.supportersTitle" />
</h2>
<p>
<FormattedHTMLMessage id="annualReport.supportersIntro" />
<FormattedMessage id="annualReport.supportersIntro" />
</p>
</div>
<div className="subsection-tag">
<FormattedHTMLMessage id="annualReport.supportersSpotlightTitle" />
<FormattedMessage id="annualReport.supportersSpotlightTitle" />
</div>
<div className="supporters-subsection">
<div className="supporters-blurb">
......@@ -2032,53 +2032,53 @@ class AnnualReport extends React.Component {
<div className="supporters-subsection supporters-lists">
<div className="supporters-blurb">
<h4>
<FormattedHTMLMessage id="annualReport.supportersThankYou" />
<FormattedMessage id="annualReport.supportersThankYou" />
</h4>
<p>
<FormattedHTMLMessage id="annualReport.supportersAllDescription" />
<FormattedMessage id="annualReport.supportersAllDescription" />
</p>
<p className="founding-partners-blurb">
<FormattedHTMLMessage id="annualReport.supportersFoundingDescription" />
<FormattedMessage id="annualReport.supportersFoundingDescription" />
</p>
</div>
<div className="supporters-level">
<h5>
<FormattedHTMLMessage id="annualReport.supportersFoundingTitle" />
<FormattedMessage id="annualReport.supportersFoundingTitle" />
</h5>
<hr />
{createSupportersLists(Supporters.founding)}
</div>
<div className="supporters-level">
<h5>
<FormattedHTMLMessage id="annualReport.supportersCreativityTitle" />
<FormattedMessage id="annualReport.supportersCreativityTitle" />
</h5>
<hr />
{createSupportersLists(Supporters.creativity)}
</div>
<div className="supporters-level">
<h5>
<FormattedHTMLMessage id="annualReport.supportersCollaborationTitle" />
<FormattedMessage id="annualReport.supportersCollaborationTitle" />
</h5>
<hr />
{createSupportersLists(Supporters.collaboration)}
</div>
<div className="supporters-level">
<h5>
<FormattedHTMLMessage id="annualReport.supportersImaginationTitle" />
<FormattedMessage id="annualReport.supportersImaginationTitle" />
</h5>
<hr />
{createSupportersLists(Supporters.imagination)}
</div>
<div className="supporters-level">
<h5>
<FormattedHTMLMessage id="annualReport.supportersInspirationTitle" />
<FormattedMessage id="annualReport.supportersInspirationTitle" />
</h5>
<hr />
{createSupportersLists(Supporters.inspiration)}
</div>
<div className="supporters-level">
<h5>
<FormattedHTMLMessage id="annualReport.supportersExplorationTitle" />
<FormattedMessage id="annualReport.supportersExplorationTitle" />
</h5>
<hr />
{createSupportersLists(Supporters.exploration)}
......@@ -2087,7 +2087,7 @@ class AnnualReport extends React.Component {
<div className="supporters-subsection supporters-lists">
<div className="supporters-level">
<h3>
<FormattedHTMLMessage id="annualReport.supportersInKindTitle" />
<FormattedMessage id="annualReport.supportersInKindTitle" />
</h3>
{createSupportersLists(Supporters.inKind)}
</div>
......@@ -2178,6 +2178,7 @@ class AnnualReport extends React.Component {
</h3>
<div className="executive-director">
<PeopleGrid
linkToNewTab
people={[{
userName: 'Champ99',
userId: 900283,
......@@ -2186,7 +2187,10 @@ class AnnualReport extends React.Component {
/>
<FormattedMessage id="annualReport.leadershipInterim" />
</div>
<PeopleGrid people={People} />
<PeopleGrid
linkToNewTab
people={People}
/>
</div>
</div>
</div>
......
......@@ -2681,12 +2681,6 @@ p {
background-color: $box-shadow-light-gray;
}
}
// Would be good to see if this works in RTL...
[dir="rtl"] a {
margin-left: 10px;
margin-right: 0px;
}
}
}
......
......@@ -255,6 +255,11 @@
"userId": 3714374,
"name": "Shruti"
},
{
"userName": "Pandatt",
"userId": 18417774,
"name": "Tracy"
},
{
"userName": "starry_sky7",
"userId": 61374093,
......
......@@ -234,6 +234,11 @@
"userId": 3714374,
"name": "Shruti"
},
{
"userName": "Pandatt",
"userId": 18417774,
"name": "Tracy"
},
{
"userName": "shaanmasala",
"userId": 29995562,
......
......@@ -43,7 +43,8 @@ class ComposeComment extends React.Component {
'isMuted',
'setupMuteExpirationTimeout'
]);
const muteExpiresAtMs = this.props.muteStatus.muteExpiresAt * 1000; // convert to ms
const muteExpiresAtMs = this.props.muteStatus.muteExpiresAt ?
this.props.muteStatus.muteExpiresAt * 1000 : 0, // convert to ms
this.state = {
message: '',
status: ComposeStatus.EDITING,
......@@ -51,6 +52,7 @@ class ComposeComment extends React.Component {
appealId: null,
muteOpen: false,
muteExpiresAtMs: muteExpiresAtMs,
muteType: this.props.muteStatus.currentMessageType,
showWarning: this.props.muteStatus.showWarning ? this.props.muteStatus.showWarning : false
};
if (this.isMuted()) {
......@@ -94,6 +96,7 @@ class ComposeComment extends React.Component {
let muteExpiresAtMs = 0;
let rejectedStatus = ComposeStatus.REJECTED;
let showWarning = false;
let muteType = null;
if (body.status && body.status.mute_status) {
muteExpiresAtMs = body.status.mute_status.muteExpiresAt * 1000; // convert to ms
rejectedStatus = ComposeStatus.REJECTED_MUTE;
......@@ -101,6 +104,7 @@ class ComposeComment extends React.Component {
muteOpen = true;
}
showWarning = body.status.mute_status.showWarning;
muteType = body.status.mute_status.muteType;
this.setupMuteExpirationTimeout(muteExpiresAtMs);
}
// Note: does not reset the message state
......@@ -110,6 +114,7 @@ class ComposeComment extends React.Component {
appealId: body.appealId,
muteOpen: muteOpen,
muteExpiresAtMs: muteExpiresAtMs,
muteType: muteType,
showWarning: showWarning
});
return;
......@@ -184,13 +189,34 @@ class ComposeComment extends React.Component {
getMuteMessageInfo () {
// return the ids for the messages that are shown for this mute type
// Note, it will probably be passed a 'type', but right now there's only one
// If mute modals have more than one unique "step" we could pass an array of steps
return {
commentType: 'comment.type.disrespectful',
muteStepHeader: 'comment.disrespectful.header',
muteStepContent: ['comment.disrespectful.content1', 'comment.disrespectful.content2']
const messageInfo = {
pii: {
commentType: 'comment.type.pii',
muteStepHeader: 'comment.pii.header',
muteStepContent: ['comment.pii.content1', 'comment.pii.content2', 'comment.pii.content3']
},
unconstructive: {
commentType: 'comment.type.unconstructive',
muteStepHeader: 'comment.unconstructive.header',
muteStepContent: ['comment.unconstructive.content1', 'comment.unconstructive.content2']
},
vulgarity: {
commentType: 'comment.type.vulgarity',
muteStepHeader: 'comment.vulgarity.header',
muteStepContent: ['comment.vulgarity.content1', 'comment.vulgar.content2']
},
general: {
commentType: 'comment.type.disrespectful',
muteStepHeader: 'comment.disrespectful.header',
muteStepContent: ['comment.disrespectful.content1', 'comment.disrespectful.content2']
}
};
if (this.state.muteType && messageInfo[this.state.muteType]) {
return messageInfo[this.state.muteType];
}
return messageInfo.general;
}
handleCancel () {
......@@ -202,6 +228,7 @@ class ComposeComment extends React.Component {
});
if (this.props.onCancel) this.props.onCancel();
}
render () {
return (
<React.Fragment>
......@@ -327,6 +354,7 @@ ComposeComment.propTypes = {
muteStatus: PropTypes.shape({
offenses: PropTypes.array,
muteExpiresAt: PropTypes.number,
currentMessageType: PropTypes.string,
showWarning: PropTypes.bool
}),
onAddComment: PropTypes.func,
......
......@@ -49,5 +49,18 @@
"comment.type.disrespectful": "Scratch thinks your most recent comment was disrespectful.",
"comment.disrespectful.header": "Make sure to be friendly and respectful when using Scratch.",
"comment.disrespectful.content1": "The Scratch comment filter thinks your comment was disrespectful.",
"comment.disrespectful.content2": "Remember: There is a person behind every Scratch account and unfriendly comments can really hurt someone's feelings."
"comment.disrespectful.content2": "Remember: There is a person behind every Scratch account and unfriendly comments can really hurt someone's feelings.",
"comment.type.pii": "The Scratch comment filter thought your most recent comment was sharing or asking for private information.",
"comment.pii.header": "Make sure not to share private information on Scratch.",
"comment.pii.content1": "The Scratch comment filter thinks that in your comment, you were sharing or asking for private information.",
"comment.pii.content2": "Things you share on Scratch can be seen by everyone, and can appear in search engines. Private information can be used by other people in harmful ways, so it’s important to keep it private.",
"comment.pii.content3": "This is a serious safety issue.",
"comment.type.unconstructive": "The Scratch comment filter thought your most recent comment was saying something bad about someone’s project.",
"comment.unconstructive.header": "Make sure to be supportive when commenting on other people’s projects",
"comment.unconstructive.content1": "The Scratch comment filter thinks your comment was saying something bad or mean about someone’s project.",
"comment.unconstructive.content2": "If you think something could be better, you can say something you like about the project, and make a suggestion about how to improve it.",
"comment.type.vulgarity": "The Scratch comment filter thought your most recent comment contained a bad word.",
"comment.vulgarity.header": "Make sure to use language that’s appropriate for all ages",
"comment.vulgarity.content1": "The Scratch comment filter thinks your comment contains a bad word.",
"comment.vulgarity.content2": "Scratch has users of all ages, so it’s important to use language that is appropriate for all Scratchers."
}
......@@ -152,6 +152,7 @@ $base-bg: $ui-white;
background-color: $ui-gray;
padding-bottom: 32px;
width: 100%;
overflow-anchor: none;
.button {
display: block;
......
This diff is collapsed.
This diff is collapsed.
......@@ -11,7 +11,8 @@ $sec-spot: $ui-blue;
.title-banner {
&.masthead {
background-color: $sec-spot;
padding: 50px 0;
padding: 50px 0 0 0;
margin: 0;
.masthead-info {
align-items: center;
......@@ -21,6 +22,10 @@ $sec-spot: $ui-blue;
justify-content: end;
}
.long {
padding-bottom: 2rem;
}
h1 {
margin: 0 0 1rem 0;
text-align: left;
......@@ -33,7 +38,28 @@ $sec-spot: $ui-blue;
max-width: $cols6;
font-size: 1.65em;
}
img {
.title-banner-button {
background-color: $ui-white;
color: $ui-blue;
font-size: 1rem;
padding: 0.75rem 1rem;
img {
margin-right: 1rem;
height: 1.2rem;
vertical-align: middle;
}
a {
color: $ui-white;
}
span {
vertical-align: middle;
}
}
.title-banner-img {
width: $cols4;
}
......@@ -57,8 +83,35 @@ $sec-spot: $ui-blue;
max-width: $cols8;
}
}
.band {
background: $ui-light-primary;
padding: 0.5rem 0;
h4.applyBanner {
color: $ui-blue;
}
}
.sec-faq {
margin-top: 3rem;
dl {
dt {
margin-bottom: .25rem;
font-size: 1.1rem;
}
dd {
margin-bottom: 1.25rem;
margin-left: 0;
max-width: $cols8;
text-align: left;
}
}
}
}
@media #{$intermediate, $medium, $small} {
#view {
text-align: left;
......
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFAB1A;}
.st1{filter:url(#Adobe_OpacityMaskFilter);}
.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st3{mask:url(#mask-2_1_);}
</style>
<desc>Created with Sketch.</desc>
<g id="Action-Menu_x2F_Actions_x2F_Surprise">
<g id="surprise-icon">
<path id="path-1_1_" class="st0" d="M7,8.7C7.8,8.4,8.4,7.8,8.7,7l0.5-1.8c0.2-0.9,1.5-0.9,1.7,0L11.3,7c0.2,0.8,0.8,1.4,1.7,1.7
l1.8,0.5c0.9,0.2,0.9,1.5,0,1.7L13,11.3c-0.8,0.2-1.4,0.8-1.7,1.7l-0.5,1.8c-0.2,0.9-1.5,0.9-1.7,0L8.7,13
c-0.2-0.8-0.8-1.4-1.7-1.7l-1.8-0.5c-0.9-0.2-0.9-1.5,0-1.7L7,8.7z M3.9,14.5c0.3-0.1,0.5-0.3,0.6-0.6l0.2-0.7
c0.1-0.3,0.5-0.3,0.6,0l0.2,0.7c0.1,0.3,0.3,0.5,0.6,0.6l0.7,0.2c0.3,0.1,0.3,0.5,0,0.6l-0.7,0.2c-0.3,0.1-0.5,0.3-0.6,0.6
l-0.2,0.7c-0.1,0.3-0.5,0.3-0.6,0l-0.2-0.7c-0.1-0.3-0.3-0.5-0.6-0.6l-0.7-0.2c-0.3-0.1-0.3-0.5,0-0.6L3.9,14.5z M13.9,4.5
c0.3-0.1,0.5-0.3,0.6-0.6l0.2-0.7c0.1-0.3,0.5-0.3,0.6,0l0.2,0.7c0.1,0.3,0.3,0.5,0.6,0.6l0.7,0.2c0.3,0.1,0.3,0.5,0,0.6l-0.7,0.2
c-0.3,0.1-0.5,0.3-0.6,0.6l-0.2,0.7c-0.1,0.3-0.5,0.3-0.6,0l-0.2-0.7c-0.1-0.3-0.3-0.5-0.6-0.6l-0.7-0.2c-0.3-0.1-0.3-0.5,0-0.6
L13.9,4.5z M5.8,5.8c0,0.4-0.3,0.8-0.8,0.8S4.2,6.2,4.2,5.8S4.6,5,5,5S5.8,5.3,5.8,5.8z M16,14.2c0,0.7-0.6,1.2-1.2,1.2
c-0.7,0-1.2-0.6-1.2-1.2c0-0.7,0.6-1.2,1.2-1.2C15.4,13,16,13.6,16,14.2z"/>
</g>
<defs>
<filter id="Adobe_OpacityMaskFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
<feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"/>
</filter>
</defs>
<mask maskUnits="userSpaceOnUse" x="0" y="0" width="20" height="20" id="mask-2_1_">
<g class="st1">
<path id="path-1_2_" class="st2" d="M7,8.7C7.8,8.4,8.4,7.8,8.7,7l0.5-1.8c0.2-0.9,1.5-0.9,1.7,0L11.3,7c0.2,0.8,0.8,1.4,1.7,1.7
l1.8,0.5c0.9,0.2,0.9,1.5,0,1.7L13,11.3c-0.8,0.2-1.4,0.8-1.7,1.7l-0.5,1.8c-0.2,0.9-1.5,0.9-1.7,0L8.7,13
c-0.2-0.8-0.8-1.4-1.7-1.7l-1.8-0.5c-0.9-0.2-0.9-1.5,0-1.7L7,8.7z M3.9,14.5c0.3-0.1,0.5-0.3,0.6-0.6l0.2-0.7
c0.1-0.3,0.5-0.3,0.6,0l0.2,0.7c0.1,0.3,0.3,0.5,0.6,0.6l0.7,0.2c0.3,0.1,0.3,0.5,0,0.6l-0.7,0.2c-0.3,0.1-0.5,0.3-0.6,0.6
l-0.2,0.7c-0.1,0.3-0.5,0.3-0.6,0l-0.2-0.7c-0.1-0.3-0.3-0.5-0.6-0.6l-0.7-0.2c-0.3-0.1-0.3-0.5,0-0.6L3.9,14.5z M13.9,4.5
c0.3-0.1,0.5-0.3,0.6-0.6l0.2-0.7c0.1-0.3,0.5-0.3,0.6,0l0.2,0.7c0.1,0.3,0.3,0.5,0.6,0.6l0.7,0.2c0.3,0.1,0.3,0.5,0,0.6
l-0.7,0.2c-0.3,0.1-0.5,0.3-0.6,0.6l-0.2,0.7c-0.1,0.3-0.5,0.3-0.6,0l-0.2-0.7c-0.1-0.3-0.3-0.5-0.6-0.6l-0.7-0.2
c-0.3-0.1-0.3-0.5,0-0.6L13.9,4.5z M5.8,5.8c0,0.4-0.3,0.8-0.8,0.8S4.2,6.2,4.2,5.8S4.6,5,5,5S5.8,5.3,5.8,5.8z M16,14.2
c0,0.7-0.6,1.2-1.2,1.2c-0.7,0-1.2-0.6-1.2-1.2c0-0.7,0.6-1.2,1.2-1.2C15.4,13,16,13.6,16,14.2z"/>
</g>
</mask>
<g id="Color_x2F_White" class="st3">
<g id="Color">
<rect class="st0" width="20" height="20"/>
</g>
</g>
</g>
</svg>
......@@ -338,4 +338,21 @@ describe('Compose Comment test', () => {
expect(commentInstance.isMuted()).toBe(false);
global.Date.now = realDateNow;
});
test('getMuteMessageInfo: muteType set', () => {
const commentInstance = getComposeCommentWrapper({}).instance();
commentInstance.setState({muteType: 'unconstructive'});
expect(commentInstance.getMuteMessageInfo().commentType).toBe('comment.type.unconstructive');
});
test('getMuteMessageInfo: muteType not set', () => {
const commentInstance = getComposeCommentWrapper({}).instance();
expect(commentInstance.getMuteMessageInfo().commentType).toBe('comment.type.disrespectful');
});
test('getMuteMessageInfo: muteType set to something we don\'t have messages for', () => {
const commentInstance = getComposeCommentWrapper({}).instance();
commentInstance.setState({muteType: 'spaghetti'});
expect(commentInstance.getMuteMessageInfo().commentType).toBe('comment.type.disrespectful');
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment