mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-23 07:38:07 -05:00
commit
15e93cc4cc
16 changed files with 500 additions and 123 deletions
|
@ -106,7 +106,9 @@ for ( var l in languages ) {
|
|||
l + '.json'
|
||||
);
|
||||
fs.accessSync(langTranslations);
|
||||
generalLocales[l] = JSON.parse(fs.readFileSync(langTranslations, 'utf8'));
|
||||
if (l !== 'en') {
|
||||
generalLocales[l] = JSON.parse(fs.readFileSync(langTranslations, 'utf8'));
|
||||
}
|
||||
} catch (err) {
|
||||
// just use english
|
||||
generalLocales[l] = generalLocales['en'];
|
||||
|
@ -128,7 +130,7 @@ var localizedAssetUrls = {};
|
|||
// - the route name
|
||||
// - the transifex resource
|
||||
// Add exceptions:
|
||||
// - txMapping: if the name of the transifex resource is different from the route name
|
||||
// - txMapping: if the name of the transifex resource is different from the route name
|
||||
var txMapping = {
|
||||
'projects': 'preview',
|
||||
'scratch_1.4': 'scratch_14' // transifex doesn't allow dots in resource names
|
||||
|
@ -228,8 +230,11 @@ async.forEachLimit(views, 5, function (view, cb) {
|
|||
}
|
||||
}
|
||||
try {
|
||||
viewLocales[isoCode] = merge({}, generalLocales[isoCode], JSON.parse(data));
|
||||
defaults(viewLocales[isoCode], viewLocales['en']);
|
||||
// don't overwrite english view strings
|
||||
if (isoCode !== 'en') {
|
||||
viewLocales[isoCode] = merge({}, generalLocales[isoCode], JSON.parse(data));
|
||||
defaults(viewLocales[isoCode], viewLocales['en']);
|
||||
}
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
"react-responsive": "3.0.0",
|
||||
"react-slick": "0.16.0",
|
||||
"react-string-replace": "0.4.1",
|
||||
"scratch-gui": "0.1.0-prerelease.20190501211108",
|
||||
"scratch-gui": "0.1.0-prerelease.20190515193432",
|
||||
"react-telephone-input": "4.3.4",
|
||||
"redux": "3.5.2",
|
||||
"redux-thunk": "2.0.1",
|
||||
|
|
114
src/components/modal/social/container.jsx
Normal file
114
src/components/modal/social/container.jsx
Normal file
|
@ -0,0 +1,114 @@
|
|||
const bindAll = require('lodash.bindall');
|
||||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const SocialModalPresentation = require('./presentation.jsx');
|
||||
const clipboardCopy = require('clipboard-copy');
|
||||
const social = require('../../../lib/social');
|
||||
|
||||
class SocialModal extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.embedTextarea = {};
|
||||
this.embedCopyTimeoutId = null;
|
||||
this.linkCopyTimeoutId = null;
|
||||
this.linkTextarea = {};
|
||||
this.showCopyResultTimeout = 2000;
|
||||
this.state = {
|
||||
showEmbedResult: false,
|
||||
showLinkResult: false
|
||||
};
|
||||
bindAll(this, [
|
||||
'handleCopyEmbed',
|
||||
'handleCopyProjectLink',
|
||||
'hideEmbedResult',
|
||||
'hideLinkResult',
|
||||
'setEmbedTextarea',
|
||||
'setLinkTextarea'
|
||||
]);
|
||||
}
|
||||
componentWillUnmount () {
|
||||
this.clearEmbedCopyResultTimeout();
|
||||
this.clearLinkCopyResultTimeout();
|
||||
}
|
||||
handleCopyEmbed () {
|
||||
if (this.embedTextarea) {
|
||||
this.embedTextarea.select();
|
||||
clipboardCopy(this.embedTextarea.value);
|
||||
if (this.state.showEmbedResult === false && this.embedCopyTimeoutId === null) {
|
||||
this.setState({showEmbedResult: true}, () => {
|
||||
this.embedCopyTimeoutId = setTimeout(
|
||||
this.hideEmbedResult,
|
||||
this.showCopyResultTimeout
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
handleCopyProjectLink () {
|
||||
if (this.linkTextarea) {
|
||||
this.linkTextarea.select();
|
||||
clipboardCopy(this.linkTextarea.value);
|
||||
if (this.state.showLinkResult === false && this.linkCopyTimeoutId === null) {
|
||||
this.setState({showLinkResult: true}, () => {
|
||||
this.linkCopyTimeoutId = setTimeout(
|
||||
this.hideLinkResult,
|
||||
this.showCopyResultTimeout
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
hideEmbedResult () {
|
||||
this.setState({showEmbedResult: false});
|
||||
this.embedCopyTimeoutId = null;
|
||||
}
|
||||
hideLinkResult () {
|
||||
this.setState({showLinkResult: false});
|
||||
this.linkCopyTimeoutId = null;
|
||||
}
|
||||
setEmbedTextarea (textarea) {
|
||||
this.embedTextarea = textarea;
|
||||
return textarea;
|
||||
}
|
||||
setLinkTextarea (textarea) {
|
||||
this.linkTextarea = textarea;
|
||||
return textarea;
|
||||
}
|
||||
clearEmbedCopyResultTimeout () {
|
||||
if (this.embedCopyTimeoutId !== null) {
|
||||
clearTimeout(this.embedCopyTimeoutId);
|
||||
this.embedCopyTimeoutId = null;
|
||||
}
|
||||
}
|
||||
clearLinkCopyResultTimeout () {
|
||||
if (this.linkCopyTimeoutId !== null) {
|
||||
clearTimeout(this.linkCopyTimeoutId);
|
||||
this.linkCopyTimeoutId = null;
|
||||
}
|
||||
}
|
||||
render () {
|
||||
const projectId = this.props.projectId;
|
||||
return (
|
||||
<SocialModalPresentation
|
||||
embedHtml={social.embedHtml(projectId)}
|
||||
isOpen={this.props.isOpen}
|
||||
projectUrl={social.projectUrl(projectId)}
|
||||
setEmbedTextarea={this.setEmbedTextarea}
|
||||
setLinkTextarea={this.setLinkTextarea}
|
||||
showEmbedResult={this.state.showEmbedResult}
|
||||
showLinkResult={this.state.showLinkResult}
|
||||
onCopyEmbed={this.handleCopyEmbed}
|
||||
onCopyProjectLink={this.handleCopyProjectLink}
|
||||
onRequestClose={this.props.onRequestClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SocialModal.propTypes = {
|
||||
isOpen: PropTypes.bool,
|
||||
onRequestClose: PropTypes.func,
|
||||
projectId: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
|
||||
};
|
||||
|
||||
module.exports = SocialModal;
|
132
src/components/modal/social/modal.scss
Normal file
132
src/components/modal/social/modal.scss
Normal file
|
@ -0,0 +1,132 @@
|
|||
@import "../../../colors";
|
||||
@import "../../../frameless";
|
||||
|
||||
.mod-social {
|
||||
min-height: 15rem;
|
||||
max-height: calc(100% - 8rem);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.social-modal-header {
|
||||
border-radius: 1rem 1rem 0 0;
|
||||
box-shadow: inset 0 -1px 0 0 $ui-blue-dark;
|
||||
background-color: $ui-blue;
|
||||
}
|
||||
|
||||
.social-modal-content {
|
||||
box-shadow: none;
|
||||
width: 92%;
|
||||
height: calc(100% - 0rem);
|
||||
margin: 1rem auto 1.625rem;
|
||||
font-size: .9375rem;
|
||||
}
|
||||
|
||||
.social-row {
|
||||
width: 100%;
|
||||
margin-top: .5rem;
|
||||
margin-bottom: .5rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.social-spaced-row {
|
||||
// width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.social-row-right {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.social-label-row {
|
||||
width: 100%;
|
||||
font-weight: bold;
|
||||
margin-bottom: .5rem;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.social-label-title {
|
||||
font-size: 1rem;
|
||||
margin-right: 1.5rem;
|
||||
}
|
||||
|
||||
.social-label-item {
|
||||
margin-left: 1.5rem;
|
||||
margin-right: .25rem;
|
||||
}
|
||||
|
||||
.social-label-result {
|
||||
color: $type-gray-75percent;
|
||||
transition: opacity 100ms linear;
|
||||
}
|
||||
|
||||
.link-section {
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.embed-section {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.social-social-icon {
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
margin-right: .75rem;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.social-twitter-icon {
|
||||
background-image: url("/images/social/twitter.png");
|
||||
}
|
||||
|
||||
.social-facebook-icon {
|
||||
background-image: url("/images/social/facebook.png");
|
||||
}
|
||||
|
||||
.social-google-classroom-icon {
|
||||
background-image: url("/images/social/google-classroom.png");
|
||||
}
|
||||
|
||||
.social-wechat-icon {
|
||||
background-image: url("/images/social/wechat.png");
|
||||
}
|
||||
|
||||
.social-form {
|
||||
transition: all .2s ease;
|
||||
border: 2px solid $box-shadow-light-gray;
|
||||
border-radius: 8px;
|
||||
background-color: $ui-blue-10percent;
|
||||
color: $type-gray;
|
||||
padding: .75rem .875rem;
|
||||
line-height: 1.25rem;
|
||||
font-size: .875rem;
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
|
||||
&:focus {
|
||||
transition: all .2s ease;
|
||||
outline: none;
|
||||
border: 2px solid $ui-blue;
|
||||
box-shadow: 0 0 0 4px $ui-blue-25percent;
|
||||
}
|
||||
|
||||
&.social-textarea {
|
||||
height: 6rem;
|
||||
}
|
||||
|
||||
&.social-input {
|
||||
height: 2.75rem;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.social-hidden {
|
||||
opacity: 0.0;
|
||||
}
|
135
src/components/modal/social/presentation.jsx
Normal file
135
src/components/modal/social/presentation.jsx
Normal file
|
@ -0,0 +1,135 @@
|
|||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const FormattedMessage = require('react-intl').FormattedMessage;
|
||||
const injectIntl = require('react-intl').injectIntl;
|
||||
const intlShape = require('react-intl').intlShape;
|
||||
const classNames = require('classnames');
|
||||
|
||||
const Modal = require('../base/modal.jsx');
|
||||
const FlexRow = require('../../flex-row/flex-row.jsx');
|
||||
|
||||
require('../../forms/button.scss');
|
||||
require('./modal.scss');
|
||||
|
||||
const SocialModalPresentation = ({
|
||||
embedHtml,
|
||||
intl,
|
||||
isOpen,
|
||||
onCopyEmbed,
|
||||
onCopyProjectLink,
|
||||
onRequestClose,
|
||||
projectUrl,
|
||||
setEmbedTextarea,
|
||||
setLinkTextarea,
|
||||
showEmbedResult,
|
||||
showLinkResult
|
||||
}) => {
|
||||
const title = intl.formatMessage({id: 'general.copyLink'});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
useStandardSizes
|
||||
className="mod-social"
|
||||
contentLabel={title}
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
>
|
||||
<div className="social-modal-header modal-header">
|
||||
<div className="social-content-label content-label">
|
||||
<FormattedMessage id="general.copyLink" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-content social-modal-content">
|
||||
|
||||
{/* top row: link */}
|
||||
<div className="link-section">
|
||||
<FlexRow className="social-row social-spaced-row">
|
||||
<FlexRow className="social-label-row">
|
||||
<div className="social-label-title">
|
||||
{intl.formatMessage({id: 'social.linkLabel'})}
|
||||
</div>
|
||||
<FlexRow className="social-spaced-row social-row-right">
|
||||
<div
|
||||
className={classNames(
|
||||
'social-label-item',
|
||||
'social-label-result',
|
||||
{'social-hidden': !showLinkResult}
|
||||
)}
|
||||
>
|
||||
{intl.formatMessage({id: 'social.embedCopiedResultText'})}
|
||||
</div>
|
||||
<div className="social-label-item">
|
||||
<a
|
||||
onClick={onCopyProjectLink}
|
||||
>
|
||||
{intl.formatMessage({id: 'social.copyLinkLinkText'})}
|
||||
</a>
|
||||
</div>
|
||||
</FlexRow>
|
||||
</FlexRow>
|
||||
<input
|
||||
readOnly
|
||||
className="social-form social-input"
|
||||
name="link"
|
||||
ref={textarea => setLinkTextarea(textarea)}
|
||||
value={projectUrl}
|
||||
/>
|
||||
</FlexRow>
|
||||
</div>
|
||||
|
||||
{/* bottom row: embed */}
|
||||
<div className="embed-section">
|
||||
<FlexRow className="social-row social-spaced-row">
|
||||
<FlexRow className="social-label-row">
|
||||
<div className="social-label-title">
|
||||
{intl.formatMessage({id: 'social.embedLabel'})}
|
||||
</div>
|
||||
<FlexRow className="social-spaced-row social-row-right">
|
||||
<div
|
||||
className={classNames(
|
||||
'social-label-item',
|
||||
'social-label-result',
|
||||
{'social-hidden': !showEmbedResult}
|
||||
)}
|
||||
>
|
||||
{intl.formatMessage({id: 'social.embedCopiedResultText'})}
|
||||
</div>
|
||||
<div className="social-label-item">
|
||||
<a
|
||||
onClick={onCopyEmbed}
|
||||
>
|
||||
{intl.formatMessage({id: 'social.copyEmbedLinkText'})}
|
||||
</a>
|
||||
</div>
|
||||
</FlexRow>
|
||||
</FlexRow>
|
||||
<textarea
|
||||
readOnly
|
||||
className="social-form social-textarea"
|
||||
name="embed"
|
||||
ref={textarea => setEmbedTextarea(textarea)}
|
||||
value={embedHtml}
|
||||
/>
|
||||
</FlexRow>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
SocialModalPresentation.propTypes = {
|
||||
embedHtml: PropTypes.string,
|
||||
intl: intlShape,
|
||||
isOpen: PropTypes.bool,
|
||||
onCopyEmbed: PropTypes.func,
|
||||
onCopyProjectLink: PropTypes.func,
|
||||
onRequestClose: PropTypes.func,
|
||||
projectUrl: PropTypes.string,
|
||||
setEmbedTextarea: PropTypes.func,
|
||||
setLinkTextarea: PropTypes.func,
|
||||
showEmbedResult: PropTypes.bool,
|
||||
showLinkResult: PropTypes.bool
|
||||
};
|
||||
|
||||
module.exports = injectIntl(SocialModalPresentation);
|
|
@ -256,5 +256,11 @@
|
|||
"comments.status.suspended": "Suspended",
|
||||
"comments.status.acctdel": "Account deleted",
|
||||
"comments.status.deleted": "Deleted",
|
||||
"comments.status.reported": "Reported"
|
||||
"comments.status.reported": "Reported",
|
||||
|
||||
"social.embedLabel": "Embed",
|
||||
"social.copyEmbedLinkText": "Copy embed",
|
||||
"social.linkLabel": "Link",
|
||||
"social.copyLinkLinkText": "Copy link",
|
||||
"social.embedCopiedResultText": "Copied"
|
||||
}
|
||||
|
|
17
src/lib/social.js
Normal file
17
src/lib/social.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
module.exports = {};
|
||||
|
||||
module.exports.projectUrl = projectId => {
|
||||
if (projectId) {
|
||||
return `https://scratch.mit.edu/projects/${projectId}`;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
module.exports.embedHtml = projectId => {
|
||||
if (projectId) {
|
||||
return `<iframe src="https://scratch.mit.edu/projects/${projectId}/embed" ` +
|
||||
'allowtransparency="true" width="485" height="402" ' +
|
||||
'frameborder="0" scrolling="no" allowfullscreen></iframe>';
|
||||
}
|
||||
return '';
|
||||
};
|
|
@ -463,7 +463,7 @@
|
|||
{
|
||||
"name": "story-tutorial-redirect",
|
||||
"pattern": "^/story/?$",
|
||||
"redirect": "/projects/editor/?tutorial=story"
|
||||
"redirect": "/projects/editor/?tutorial=tell-a-story"
|
||||
},
|
||||
{
|
||||
"name": "pong-tutorial-redirect",
|
||||
|
|
|
@ -53,7 +53,7 @@ const ConferenceSplash = () => (
|
|||
src="/svgs/conference/flags/cl.svg"
|
||||
/>
|
||||
<div className="conf2019-panel-title-text">
|
||||
<h3>Conferencia Scratch al Sur</h3>
|
||||
<h3>Scratch al Sur Conferencia Chile 2019</h3>
|
||||
</div>
|
||||
</FlexRow>
|
||||
<p className="conf2019-panel-desc">
|
||||
|
@ -141,104 +141,7 @@ const ConferenceSplash = () => (
|
|||
<FormattedMessage id="conference-2019.website" />
|
||||
</a>
|
||||
</section>
|
||||
<section className="conf2019-panel mod-kenya">
|
||||
<FlexRow className="conf2019-panel-title">
|
||||
<img
|
||||
alt="Kenya Flag"
|
||||
className="conf2019-panel-flag"
|
||||
src="/svgs/conference/flags/ke.svg"
|
||||
/>
|
||||
<div className="conf2019-panel-title-text">
|
||||
<h3><FormattedMessage id="conference-2019.kenyaTitle" /></h3>
|
||||
<h4><FormattedMessage id="conference-2019.kenyaSubTitle" /></h4>
|
||||
</div>
|
||||
</FlexRow>
|
||||
<p className="conf2019-panel-desc">
|
||||
<FormattedMessage id="conference-2019.kenyaDesc" />
|
||||
</p>
|
||||
<table className="conf2019-panel-details">
|
||||
<tbody>
|
||||
<tr className="conf2019-panel-row">
|
||||
<td className="conf2019-panel-row-icon">
|
||||
<img
|
||||
alt="Calendar Icon"
|
||||
className="conf2019-panel-row-icon-image"
|
||||
src="/svgs/conference/index/calendar-icon-solid.svg"
|
||||
/>
|
||||
</td>
|
||||
<td><FormattedMessage id="conference-2019.date" /></td>
|
||||
<td>
|
||||
<FormattedDate
|
||||
day="2-digit"
|
||||
month="long"
|
||||
value={new Date(2019, 6, 8)}
|
||||
year="numeric"
|
||||
/>
|
||||
{' - '}
|
||||
<FormattedDate
|
||||
day="2-digit"
|
||||
month="long"
|
||||
value={new Date(2019, 6, 13)}
|
||||
year="numeric"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="conf2019-panel-row">
|
||||
<td className="conf2019-panel-row-icon">
|
||||
<img
|
||||
alt="Map Icon"
|
||||
className="conf2019-panel-row-icon-image"
|
||||
src="/svgs/conference/index/map-icon-solid.svg"
|
||||
/>
|
||||
</td>
|
||||
<td><FormattedMessage id="conference-2019.location" /></td>
|
||||
<td>{'Nairobi, Kenya'}</td>
|
||||
</tr>
|
||||
<tr className="conf2019-panel-row">
|
||||
<td className="conf2019-panel-row-icon">
|
||||
<img
|
||||
alt="Audience Icon"
|
||||
className="conf2019-panel-row-icon-image"
|
||||
src="/svgs/conference/index/audience-icon-solid.svg"
|
||||
/>
|
||||
</td>
|
||||
<td><FormattedMessage id="conference-2019.audience" /></td>
|
||||
<td><FormattedMessage id="conference-2019.kenyaAudience" /></td>
|
||||
</tr>
|
||||
<tr className="conf2019-panel-row">
|
||||
<td className="conf2019-panel-row-icon">
|
||||
<img
|
||||
alt="Language Icon"
|
||||
className="conf2019-panel-row-icon-image"
|
||||
src="/svgs/conference/index/language-icon-solid.svg"
|
||||
/>
|
||||
</td>
|
||||
<td><FormattedMessage id="conference-2019.language" /></td>
|
||||
<td><FormattedMessage id="general.english" /></td>
|
||||
</tr>
|
||||
<tr className="conf2019-panel-row">
|
||||
<td className="conf2019-panel-row-icon">
|
||||
<img
|
||||
alt="Language Icon"
|
||||
className="conf2019-panel-row-icon-image"
|
||||
src="/svgs/conference/index/hashtag-icon-solid.svg"
|
||||
/>
|
||||
</td>
|
||||
<td><FormattedMessage id="conference-2019.hashtag" /></td>
|
||||
<td>{'#Scratch2019AFR'}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<a
|
||||
className="button mod-2019-conf mod-2019-conf-website-button"
|
||||
href="https://www.scratchafrica.com"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage id="conference-2019.website" />
|
||||
</a>
|
||||
</section>
|
||||
<section className="conf2019-panel mod-uk mod-last">
|
||||
<section className="conf2019-panel mod-uk">
|
||||
<FlexRow className="conf2019-panel-title">
|
||||
<img
|
||||
alt="EU Flag"
|
||||
|
@ -327,13 +230,28 @@ const ConferenceSplash = () => (
|
|||
</table>
|
||||
<a
|
||||
className="button mod-2019-conf mod-2019-conf-website-button"
|
||||
href="https://www.raspberrypi.org/blog/announcing-scratch-conference-europe-2019/"
|
||||
href="https://scratchconferenceeurope.raspberrypi.org/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage id="conference-2019.website" />
|
||||
</a>
|
||||
</section>
|
||||
<section className="conf2019-panel mod-kenya mod-last">
|
||||
<FlexRow className="conf2019-panel-title">
|
||||
<img
|
||||
alt="Kenya Flag"
|
||||
className="conf2019-panel-flag"
|
||||
src="/svgs/conference/flags/ke.svg"
|
||||
/>
|
||||
<div className="conf2019-panel-title-text">
|
||||
<h3><FormattedMessage id="conference-2019.kenyaTitle" /></h3>
|
||||
</div>
|
||||
</FlexRow>
|
||||
<p className="conf2019-panel-desc">
|
||||
<FormattedMessage id="conference-2019.kenyaPostpone" />
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
<div className="conf2019-title-band conf2019-mailing-list">
|
||||
<img
|
||||
|
|
|
@ -99,6 +99,7 @@ h1.title-banner-h1.mod-2019 {
|
|||
|
||||
.conf2019-panel.mod-last {
|
||||
border-bottom: 0;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.flex-row.conf2019-panel-title {
|
||||
|
@ -118,6 +119,12 @@ h1.title-banner-h1.mod-2019 {
|
|||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.mod-kenya {
|
||||
.conf2019-panel-desc {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.conf2019-mailing-list {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
|
|
@ -23,9 +23,10 @@
|
|||
"conference-2019.kenyaTitle": "Scratch2019NBO",
|
||||
"conference-2019.kenyaSubTitle": "Waves of Innovation",
|
||||
"conference-2019.kenyaDesc": "In recognition of Africa's technological contributions to the world and the potential of the youth of Africa, Scratch2019NBO will be held in Nairobi, Kenya. Join educators from around the world to share lessons, empower young people, and celebrate accomplishments in creative coding.",
|
||||
"conference-2019.kenyaPostpone": "The Scratch2019NBO conference, originally planned for Nairobi, Kenya in July 2019, has been postponed. Information about future plans will be available later this year.",
|
||||
"conference-2019.kenyaAudience": "Educators, students, and enthusiasts",
|
||||
|
||||
"conference-2019.chileDesc": "Scratch al Sur is a gathering for teachers and policy makers to learn about the importance of introducing programming languages in schools. All lectures and workshops will provide an opportunity to share different experiences, from higher levels to those who are beginning to participate in Scratch's global community.",
|
||||
"conference-2019.chileDesc": "Scratch al Sur Conferencia Chile 2019 is an event aimed at teachers of all educational areas and levels, who seek to innovate in the classroom through creative learning, thus supporting public policies that are promoted through the National Plan of Digital Languages, launched by the Chilean government as of 2019. Various workshops, panels, experiences, stands, a presentation of the new Scratch 3.0, Makey-Makey, and much more will be offered.",
|
||||
"conference-2019.chileAudience": "Teachers and policy makers",
|
||||
"conference-2019.spanishWithSimultaneous": "Spanish - simultaneous translation into English during plenary sessions"
|
||||
}
|
||||
|
|
|
@ -111,7 +111,10 @@ class Comment extends React.Component {
|
|||
visibility
|
||||
} = this.props;
|
||||
|
||||
const visible = visibility === 'visible';
|
||||
// we allow comments that are fully visible, or markedByFilter (flagged by
|
||||
// our bad words filter, but not at the critical level of offensiveness)
|
||||
const markedByFilter = visibility === 'markedbyfilter';
|
||||
const visible = markedByFilter || visibility === 'visible';
|
||||
|
||||
let commentText = content;
|
||||
if (replyUsername) {
|
||||
|
@ -182,6 +185,7 @@ class Comment extends React.Component {
|
|||
<div
|
||||
className={classNames({
|
||||
'comment-bubble': true,
|
||||
'comment-bubble-markedbyfilter': markedByFilter,
|
||||
'comment-bubble-reported': !visible
|
||||
})}
|
||||
>
|
||||
|
|
|
@ -197,6 +197,19 @@
|
|||
background: $reported-background;
|
||||
}
|
||||
}
|
||||
|
||||
&.comment-bubble-markedbyfilter {
|
||||
$markedbyfilter-outline: $ui-yellow;
|
||||
$markedbyfilter-background: rgb(255, 254, 210);
|
||||
|
||||
border-color: $markedbyfilter-outline;
|
||||
background-color: $markedbyfilter-background;
|
||||
|
||||
&:before {
|
||||
border-color: $markedbyfilter-outline transparent $markedbyfilter-outline $markedbyfilter-outline;
|
||||
background: $markedbyfilter-background;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.comment-content {
|
||||
|
|
|
@ -88,7 +88,6 @@ const PreviewPresentation = ({
|
|||
onAddToStudioClicked,
|
||||
onAddToStudioClosed,
|
||||
onCloseAdminPanel,
|
||||
onCopyProjectLink,
|
||||
onDeleteComment,
|
||||
onFavoriteClicked,
|
||||
onGreenFlag,
|
||||
|
@ -108,6 +107,8 @@ const PreviewPresentation = ({
|
|||
onSeeInside,
|
||||
onSetProjectThumbnailer,
|
||||
onShare,
|
||||
onSocialClicked,
|
||||
onSocialClosed,
|
||||
onToggleComments,
|
||||
onToggleStudio,
|
||||
onUpdateProjectId,
|
||||
|
@ -126,6 +127,7 @@ const PreviewPresentation = ({
|
|||
showAdminPanel,
|
||||
showModInfo,
|
||||
singleCommentId,
|
||||
socialOpen,
|
||||
userOwnsProject,
|
||||
visibilityInfo
|
||||
}) => {
|
||||
|
@ -368,13 +370,15 @@ const PreviewPresentation = ({
|
|||
projectInfo={projectInfo}
|
||||
reportOpen={reportOpen}
|
||||
shareDate={shareDate}
|
||||
socialOpen={socialOpen}
|
||||
userOwnsProject={userOwnsProject}
|
||||
onAddToStudioClicked={onAddToStudioClicked}
|
||||
onAddToStudioClosed={onAddToStudioClosed}
|
||||
onCopyProjectLink={onCopyProjectLink}
|
||||
onReportClicked={onReportClicked}
|
||||
onReportClose={onReportClose}
|
||||
onReportSubmit={onReportSubmit}
|
||||
onSocialClicked={onSocialClicked}
|
||||
onSocialClosed={onSocialClosed}
|
||||
onToggleStudio={onToggleStudio}
|
||||
/>
|
||||
</div>
|
||||
|
@ -514,13 +518,15 @@ const PreviewPresentation = ({
|
|||
projectInfo={projectInfo}
|
||||
reportOpen={reportOpen}
|
||||
shareDate={shareDate}
|
||||
socialOpen={socialOpen}
|
||||
userOwnsProject={userOwnsProject}
|
||||
onAddToStudioClicked={onAddToStudioClicked}
|
||||
onAddToStudioClosed={onAddToStudioClosed}
|
||||
onCopyProjectLink={onCopyProjectLink}
|
||||
onReportClicked={onReportClicked}
|
||||
onReportClose={onReportClose}
|
||||
onReportSubmit={onReportSubmit}
|
||||
onSocialClicked={onSocialClicked}
|
||||
onSocialClosed={onSocialClosed}
|
||||
onToggleStudio={onToggleStudio}
|
||||
/>
|
||||
</FlexRow>
|
||||
|
@ -693,7 +699,6 @@ PreviewPresentation.propTypes = {
|
|||
onAddToStudioClicked: PropTypes.func,
|
||||
onAddToStudioClosed: PropTypes.func,
|
||||
onCloseAdminPanel: PropTypes.func,
|
||||
onCopyProjectLink: PropTypes.func,
|
||||
onDeleteComment: PropTypes.func,
|
||||
onFavoriteClicked: PropTypes.func,
|
||||
onGreenFlag: PropTypes.func,
|
||||
|
@ -713,6 +718,8 @@ PreviewPresentation.propTypes = {
|
|||
onSeeInside: PropTypes.func,
|
||||
onSetProjectThumbnailer: PropTypes.func,
|
||||
onShare: PropTypes.func,
|
||||
onSocialClicked: PropTypes.func,
|
||||
onSocialClosed: PropTypes.func,
|
||||
onToggleComments: PropTypes.func,
|
||||
onToggleStudio: PropTypes.func,
|
||||
onUpdateProjectId: PropTypes.func,
|
||||
|
@ -731,6 +738,7 @@ PreviewPresentation.propTypes = {
|
|||
showModInfo: PropTypes.bool,
|
||||
showUsernameBlockAlert: PropTypes.bool,
|
||||
singleCommentId: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
|
||||
socialOpen: PropTypes.bool,
|
||||
userOwnsProject: PropTypes.bool,
|
||||
visibilityInfo: PropTypes.shape({
|
||||
censored: PropTypes.bool,
|
||||
|
|
|
@ -8,7 +8,6 @@ const PropTypes = require('prop-types');
|
|||
const connect = require('react-redux').connect;
|
||||
const injectIntl = require('react-intl').injectIntl;
|
||||
const parser = require('scratch-parser');
|
||||
const copy = require('clipboard-copy');
|
||||
|
||||
const Page = require('../../components/page/www/page.jsx');
|
||||
const storage = require('../../lib/storage.js').default;
|
||||
|
@ -55,8 +54,9 @@ class Preview extends React.Component {
|
|||
'fetchCommunityData',
|
||||
'handleAddComment',
|
||||
'handleClickLogo',
|
||||
'handleCopyProjectLink',
|
||||
'handleDeleteComment',
|
||||
'handleSocialClick',
|
||||
'handleSocialClose',
|
||||
'handleToggleStudio',
|
||||
'handleFavoriteToggle',
|
||||
'handleLoadMore',
|
||||
|
@ -109,6 +109,7 @@ class Preview extends React.Component {
|
|||
clientFaved: false,
|
||||
clientLoved: false,
|
||||
extensions: [],
|
||||
socialOpen: false,
|
||||
favoriteCount: 0,
|
||||
isProjectLoaded: false,
|
||||
isRemixing: false,
|
||||
|
@ -381,6 +382,12 @@ class Preview extends React.Component {
|
|||
handleAddToStudioClose () {
|
||||
this.setState({addToStudioOpen: false});
|
||||
}
|
||||
handleSocialClick () {
|
||||
this.setState({socialOpen: true});
|
||||
}
|
||||
handleSocialClose () {
|
||||
this.setState({socialOpen: false});
|
||||
}
|
||||
handleReportSubmit (formData) {
|
||||
const submit = data => this.props.reportProject(this.state.projectId, data, this.props.user.token);
|
||||
if (this.getProjectThumbnail) {
|
||||
|
@ -579,11 +586,6 @@ class Preview extends React.Component {
|
|||
this.props.user.token
|
||||
);
|
||||
}
|
||||
handleCopyProjectLink () {
|
||||
// Use the pathname so we do not have to update this if path changes
|
||||
// Also do not include hash or query params
|
||||
copy(`${window.location.origin}${window.location.pathname}`);
|
||||
}
|
||||
initCounts (favorites, loves) {
|
||||
this.setState({
|
||||
favoriteCount: favorites,
|
||||
|
@ -678,13 +680,13 @@ class Preview extends React.Component {
|
|||
showModInfo={this.props.isAdmin}
|
||||
showUsernameBlockAlert={this.state.showUsernameBlockAlert}
|
||||
singleCommentId={this.state.singleCommentId}
|
||||
socialOpen={this.state.socialOpen}
|
||||
userOwnsProject={this.props.userOwnsProject}
|
||||
visibilityInfo={this.props.visibilityInfo}
|
||||
onAddComment={this.handleAddComment}
|
||||
onAddToStudioClicked={this.handleAddToStudioClick}
|
||||
onAddToStudioClosed={this.handleAddToStudioClose}
|
||||
onCloseAdminPanel={this.handleCloseAdminPanel}
|
||||
onCopyProjectLink={this.handleCopyProjectLink}
|
||||
onDeleteComment={this.handleDeleteComment}
|
||||
onFavoriteClicked={this.handleFavoriteToggle}
|
||||
onGreenFlag={this.handleGreenFlag}
|
||||
|
@ -704,6 +706,8 @@ class Preview extends React.Component {
|
|||
onSeeInside={this.handleSeeInside}
|
||||
onSetProjectThumbnailer={this.handleSetProjectThumbnailer}
|
||||
onShare={this.handleShare}
|
||||
onSocialClicked={this.handleSocialClick}
|
||||
onSocialClosed={this.handleSocialClose}
|
||||
onToggleComments={this.handleToggleComments}
|
||||
onToggleStudio={this.handleToggleStudio}
|
||||
onUpdateProjectId={this.handleUpdateProjectId}
|
||||
|
|
|
@ -6,7 +6,9 @@ const FlexRow = require('../../components/flex-row/flex-row.jsx');
|
|||
|
||||
const Button = require('../../components/forms/button.jsx');
|
||||
const AddToStudioModal = require('./add-to-studio.jsx');
|
||||
const SocialModal = require('../../components/modal/social/container.jsx');
|
||||
const ReportModal = require('../../components/modal/report/modal.jsx');
|
||||
const projectShape = require('./projectshape.jsx').projectShape;
|
||||
|
||||
require('./subactions.scss');
|
||||
|
||||
|
@ -50,10 +52,18 @@ const Subactions = props => (
|
|||
}
|
||||
<Button
|
||||
className="action-button copy-link-button"
|
||||
onClick={props.onCopyProjectLink}
|
||||
onClick={props.onSocialClicked}
|
||||
>
|
||||
<FormattedMessage id="general.copyLink" />
|
||||
</Button>
|
||||
{props.socialOpen && props.projectInfo && props.projectInfo.id && (
|
||||
<SocialModal
|
||||
isOpen
|
||||
key="social-modal"
|
||||
projectId={props.projectInfo && props.projectInfo.id}
|
||||
onRequestClose={props.onSocialClosed}
|
||||
/>
|
||||
)}
|
||||
{(props.canReport) &&
|
||||
<React.Fragment>
|
||||
<Button
|
||||
|
@ -85,13 +95,16 @@ Subactions.propTypes = {
|
|||
isAdmin: PropTypes.bool,
|
||||
onAddToStudioClicked: PropTypes.func,
|
||||
onAddToStudioClosed: PropTypes.func,
|
||||
onCopyProjectLink: PropTypes.func,
|
||||
onReportClicked: PropTypes.func.isRequired,
|
||||
onReportClose: PropTypes.func.isRequired,
|
||||
onReportSubmit: PropTypes.func.isRequired,
|
||||
onSocialClicked: PropTypes.func,
|
||||
onSocialClosed: PropTypes.func,
|
||||
onToggleStudio: PropTypes.func,
|
||||
projectInfo: projectShape,
|
||||
reportOpen: PropTypes.bool,
|
||||
shareDate: PropTypes.string,
|
||||
socialOpen: PropTypes.bool,
|
||||
userOwnsProject: PropTypes.bool
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue