diff --git a/bin/build-locales b/bin/build-locales index 0c2c20d4d..d9af2135b 100755 --- a/bin/build-locales +++ b/bin/build-locales @@ -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); } diff --git a/package.json b/package.json index 8036a319a..9bdb98d5e 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/modal/social/container.jsx b/src/components/modal/social/container.jsx new file mode 100644 index 000000000..876e88c19 --- /dev/null +++ b/src/components/modal/social/container.jsx @@ -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 ( + + ); + } +} + +SocialModal.propTypes = { + isOpen: PropTypes.bool, + onRequestClose: PropTypes.func, + projectId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) +}; + +module.exports = SocialModal; diff --git a/src/components/modal/social/modal.scss b/src/components/modal/social/modal.scss new file mode 100644 index 000000000..be290d21e --- /dev/null +++ b/src/components/modal/social/modal.scss @@ -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; +} diff --git a/src/components/modal/social/presentation.jsx b/src/components/modal/social/presentation.jsx new file mode 100644 index 000000000..afd0b3981 --- /dev/null +++ b/src/components/modal/social/presentation.jsx @@ -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 ( + +
+
+ +
+
+
+ + {/* top row: link */} +
+ + +
+ {intl.formatMessage({id: 'social.linkLabel'})} +
+ +
+ {intl.formatMessage({id: 'social.embedCopiedResultText'})} +
+ +
+
+ setLinkTextarea(textarea)} + value={projectUrl} + /> +
+
+ + {/* bottom row: embed */} +
+ + +
+ {intl.formatMessage({id: 'social.embedLabel'})} +
+ +
+ {intl.formatMessage({id: 'social.embedCopiedResultText'})} +
+ +
+
+