diff --git a/package-lock.json b/package-lock.json index 5a6627281..9c84ca3dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,9 +101,9 @@ "optional": true }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -503,9 +503,9 @@ } }, "electron-to-chromium": { - "version": "1.3.726", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.726.tgz", - "integrity": "sha512-dw7WmrSu/JwtACiBzth8cuKf62NKL1xVJuNvyOg0jvruN/n4NLtGYoTzciQquCPNaS2eR+BT5GrxHbslfc/w1w==", + "version": "1.3.727", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.727.tgz", + "integrity": "sha512-Mfz4FIB4FSvEwBpDfdipRIrwd6uo8gUDoRDF4QEYb4h4tSuI3ov594OrjU6on042UlFHouIJpClDODGkPcBSbg==", "dev": true }, "semver": { @@ -1368,27 +1368,10 @@ } } }, - "@formatjs/ecma402-abstract": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.7.0.tgz", - "integrity": "sha512-0IQF4oDZdO8ruyrNJZuRle3F/YiGgRwTNrZyMI1N1X8GERZusOrXU9Stw+j/lyyfDWaJK44b+Qnri/qfLPCtGQ==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - }, - "dependencies": { - "tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", - "dev": true - } - } - }, "@formatjs/intl-getcanonicallocales": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@formatjs/intl-getcanonicallocales/-/intl-getcanonicallocales-1.5.9.tgz", - "integrity": "sha512-bO0J3IaamFM3rU7noXo1bWSmPA8xuAL8NPk+k5Dy08ehiu/STT3sN+6DGLEvRCpb465CpjUWGCNknDFIcdu9hA==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/@formatjs/intl-getcanonicallocales/-/intl-getcanonicallocales-1.5.10.tgz", + "integrity": "sha512-tFqGxZ9HkAzphupybyCKdWHzL1ge/sY8TtzEK57Hs3RCxrv/y+VxIPrE+Izw2oCFowQBz76cyi0zT6PjHuWArA==", "dev": true, "requires": { "cldr-core": "38", @@ -1404,21 +1387,21 @@ } }, "@formatjs/intl-locale": { - "version": "2.4.23", - "resolved": "https://registry.npmjs.org/@formatjs/intl-locale/-/intl-locale-2.4.23.tgz", - "integrity": "sha512-5G0SjOsVxmX79dPaYk6KWxtdQ18UNK+E2JtAXvGxP8rSMqbJ/7cpDg95CU+YBXVKn6pRWefwqBsbjT5l+kK3yQ==", + "version": "2.4.24", + "resolved": "https://registry.npmjs.org/@formatjs/intl-locale/-/intl-locale-2.4.24.tgz", + "integrity": "sha512-+JOwvBRFS/GFuJlWiWbfAzBng0A+ANoGV1LRseXK+4uzp4Sn35GD8M/dfgU1lp2R2dTWpYie2yyoHe4k4aHF6w==", "dev": true, "requires": { - "@formatjs/ecma402-abstract": "1.7.0", - "@formatjs/intl-getcanonicallocales": "1.5.9", + "@formatjs/ecma402-abstract": "1.7.1", + "@formatjs/intl-getcanonicallocales": "1.5.10", "cldr-core": "38", "tslib": "^2.1.0" }, "dependencies": { "@formatjs/ecma402-abstract": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.7.0.tgz", - "integrity": "sha512-0IQF4oDZdO8ruyrNJZuRle3F/YiGgRwTNrZyMI1N1X8GERZusOrXU9Stw+j/lyyfDWaJK44b+Qnri/qfLPCtGQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.7.1.tgz", + "integrity": "sha512-FjewVLB2DVEVCvvC7IMffzXVhysvi442i6ed0H7qcrT6xtUpO4vr0oZgpOmsv6D9I4Io0GVebIuySwteS/k3gg==", "dev": true, "requires": { "tslib": "^2.1.0" @@ -1433,15 +1416,24 @@ } }, "@formatjs/intl-pluralrules": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@formatjs/intl-pluralrules/-/intl-pluralrules-4.0.17.tgz", - "integrity": "sha512-SOX7lRrM1DQXZSzqoCztT+Gc6lnnoqGAVrX/YivQ7J8miPfxN8vgZhZN0MiEGPSLV0HJdO+AA+Xu0hUNJPlpnQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@formatjs/intl-pluralrules/-/intl-pluralrules-4.0.18.tgz", + "integrity": "sha512-qRFITPsNoeXfsiGc97pp8mVgqcC7aQNuXsiJjY9LpXVTkYNfjUP4ZpbYXflM4xoWCXMJNz3ilsrQhZWXy9td5g==", "dev": true, "requires": { - "@formatjs/ecma402-abstract": "1.7.0", + "@formatjs/ecma402-abstract": "1.7.1", "tslib": "^2.1.0" }, "dependencies": { + "@formatjs/ecma402-abstract": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.7.1.tgz", + "integrity": "sha512-FjewVLB2DVEVCvvC7IMffzXVhysvi442i6ed0H7qcrT6xtUpO4vr0oZgpOmsv6D9I4Io0GVebIuySwteS/k3gg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, "tslib": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", @@ -1451,15 +1443,24 @@ } }, "@formatjs/intl-relativetimeformat": { - "version": "8.1.7", - "resolved": "https://registry.npmjs.org/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-8.1.7.tgz", - "integrity": "sha512-S8OoqOwiSqU/T0umkjB2lZcyWS4Dh8sWd4m8V+MsSnraeijNho/wSXQhJAuHx0b2Xvnlddt7a5RwyUnLADUepA==", + "version": "8.1.8", + "resolved": "https://registry.npmjs.org/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-8.1.8.tgz", + "integrity": "sha512-MIVrsgG7hvYrnes6TxJLflXhhTuxIaWCIdf6p5Iv6HguTtDJqqAFOCNRCqUnYQeYcNbgIQBgLb0Kh7djS0GU+w==", "dev": true, "requires": { - "@formatjs/ecma402-abstract": "1.7.0", + "@formatjs/ecma402-abstract": "1.7.1", "tslib": "^2.1.0" }, "dependencies": { + "@formatjs/ecma402-abstract": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.7.1.tgz", + "integrity": "sha512-FjewVLB2DVEVCvvC7IMffzXVhysvi442i6ed0H7qcrT6xtUpO4vr0oZgpOmsv6D9I4Io0GVebIuySwteS/k3gg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, "tslib": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", @@ -10518,9 +10519,9 @@ } }, "handlebars": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "requires": { "minimist": "^1.2.5", @@ -10543,9 +10544,9 @@ "dev": true }, "uglify-js": { - "version": "3.11.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.11.2.tgz", - "integrity": "sha512-G440NU6fewtnQftSgqRV1r2A5ChKbU1gqFCJ7I8S7MPpY/eZZfLGefaY6gUZYiWebMaO+txgiQ1ZyLDuNWJulg==", + "version": "3.13.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.5.tgz", + "integrity": "sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw==", "dev": true, "optional": true } @@ -10814,9 +10815,9 @@ } }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "hsluv": { @@ -18918,9 +18919,9 @@ }, "dependencies": { "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -20855,9 +20856,9 @@ } }, "scratch-blocks": { - "version": "0.1.0-prerelease.20210505033858", - "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20210505033858.tgz", - "integrity": "sha512-qsHsxVsXvB7cZnoLirkl+HRjj+X7VcJh9Rh7UX8JoMEJsfUfTRJfo3wSt7zv4iKx6EK/QIStQNs9AACSPVaA7Q==", + "version": "0.1.0-prerelease.20210509032512", + "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20210509032512.tgz", + "integrity": "sha512-rgQrbtSXxCzuuiMdyX/HGhiP8eOX8yDG9ncML9ykgnaDF8ZnfflLD201GwfyvOv3D51Nu6w2Ktg0PcF3ZqnH2Q==", "dev": true, "requires": { "exports-loader": "0.6.3", @@ -20865,9 +20866,9 @@ } }, "scratch-gui": { - "version": "0.1.0-prerelease.20210505040706", - "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-0.1.0-prerelease.20210505040706.tgz", - "integrity": "sha512-KyHm41UAlIKomysMzXqKMkibs6WsibC2jCX/AbsYR47UNtFJLhjvUyJKv05EbGo9GAr/b1uRglTRtiXA8SWsvw==", + "version": "0.1.0-prerelease.20210509040505", + "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-0.1.0-prerelease.20210509040505.tgz", + "integrity": "sha512-mXyQxytn3tnes2wiuNG9vnSFQ4anoDxkTHMLS2Xro91M5xP+KVgaR+60yWQegsBnz/8LAA+HTlKadHhr/t+PLQ==", "dev": true, "requires": { "arraybuffer-loader": "^1.0.6", @@ -20918,8 +20919,8 @@ "redux": "3.7.2", "redux-throttle": "0.1.1", "scratch-audio": "0.1.0-prerelease.20200528195344", - "scratch-blocks": "0.1.0-prerelease.20210505033858", - "scratch-l10n": "3.11.20210504031549", + "scratch-blocks": "0.1.0-prerelease.20210509032512", + "scratch-l10n": "3.11.20210509031637", "scratch-paint": "0.2.0-prerelease.20210407203313", "scratch-render": "0.1.0-prerelease.20210325231800", "scratch-render-fonts": "1.0.0-prerelease.20210401210003", @@ -21311,9 +21312,9 @@ "dev": true }, "scratch-l10n": { - "version": "3.11.20210504031549", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.11.20210504031549.tgz", - "integrity": "sha512-R6CfX0p8LegrsqKm5s+8cSlvzg8Ijma4zGOet22yVtJbtSEcmFmi3LbwV5cKKPjoDWobZMYUhrazmlBLswKPQw==", + "version": "3.11.20210509031637", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.11.20210509031637.tgz", + "integrity": "sha512-MtO6InGeR6WCtJRlPSnnphWQGwv1bLZ8m7tWczF3kQeZopESq7iy36TkHdPioQ9NnptCtQw1xgeyVakuKbNGxg==", "dev": true, "requires": { "@babel/cli": "^7.1.2", @@ -21400,9 +21401,9 @@ } }, "scratch-l10n": { - "version": "3.11.20210505031459", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.11.20210505031459.tgz", - "integrity": "sha512-1geGseNJ95UIyKaOWYIkdE0V2mSUxcrGR/wUE86727FqwYdo19nJyaXvzcv2mWWGdvDu3eV7ei3raD1ZXAniSA==", + "version": "3.11.20210510031549", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.11.20210510031549.tgz", + "integrity": "sha512-WeoSa4zxtOcAGeaASqVcJcZu/QWoWtHohsP71ICbNcBpcAqnpPV1AhdGNrOQyiwuj0Vy/6CBuH9QYpS0IF+AkA==", "dev": true, "requires": { "@babel/cli": "^7.1.2", @@ -25851,9 +25852,9 @@ "dev": true }, "ua-parser-js": { - "version": "0.7.20", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.20.tgz", - "integrity": "sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==", + "version": "0.7.28", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz", + "integrity": "sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==", "dev": true }, "uglify-js": { diff --git a/package.json b/package.json index 1b954f597..01ffec3d7 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "redux-mock-store": "^1.2.3", "redux-thunk": "2.0.1", "sass-loader": "6.0.6", - "scratch-gui": "0.1.0-prerelease.20210505040706", + "scratch-gui": "0.1.0-prerelease.20210509040505", "scratch-l10n": "latest", "selenium-webdriver": "3.6.0", "slick-carousel": "1.6.0", diff --git a/src/_colors.scss b/src/_colors.scss index 5401a6541..495c84469 100644 --- a/src/_colors.scss +++ b/src/_colors.scss @@ -26,6 +26,7 @@ $background-color: hsla(0, 0, 99, 1); //#FDFDFD /* 3.0 colors */ /* Using www naming convention for now, should be consistent with gui */ $ui-aqua: hsla(163, 85, 40, 1); // #0FBD8C Extension Primary +$ui-aqua-dark: hsla(163, 85, 30, 1); // #0B8E69 Extension Aqua 3 $ui-purple: hsla(260, 100, 70, 1); // #9966FF Looks Primary $ui-purple-dark: hsla(260, 60, 60, 1); // #774DCB Looks Secondary $ui-magenta: hsla(300, 53%, 60%, 1); /* #CF63CF Sounds Primary */ diff --git a/src/components/forms/button.jsx b/src/components/forms/button.jsx index b5b97e39a..39bab920a 100644 --- a/src/components/forms/button.jsx +++ b/src/components/forms/button.jsx @@ -6,21 +6,38 @@ const React = require('react'); require('./button.scss'); const Button = props => { - const classes = classNames('button', props.className); + const classes = classNames('button', props.className, {'close-button': props.isCloseType}); return ( ); }; Button.propTypes = { children: PropTypes.node, - className: PropTypes.string + className: PropTypes.string, + isCloseType: PropTypes.bool +}; + +Button.defaultProps = { + className: '', + isCloseType: false }; module.exports = Button; diff --git a/src/components/forms/button.scss b/src/components/forms/button.scss index 3a88a61f4..a09931f5b 100644 --- a/src/components/forms/button.scss +++ b/src/components/forms/button.scss @@ -53,3 +53,22 @@ $pass-bg: $ui-aqua; margin-right: -.25rem; } } + +.close-button { + padding: 0; + + position: absolute; + top: 0.5rem; + right: 0.5rem; + border-radius: 1rem; + background-color: $active-gray; + cursor: pointer; + width: 2rem; + height: 2rem; + text-align: center; + line-height: 2rem; +} + +.close-button img { + padding-top: 0.5rem; +} diff --git a/src/l10n.json b/src/l10n.json index 48859e7b4..35ebb79e6 100644 --- a/src/l10n.json +++ b/src/l10n.json @@ -248,6 +248,7 @@ "thumbnail.by": "by", "report.error": "Something went wrong when trying to send your message. Please try again.", "report.project": "Report Project", + "report.studio": "Report Studio", "report.projectInstructions": "When you send a report, it lets the Scratch Team know about projects that break the {CommunityGuidelinesLink}. Does something in this project break the {CommunityGuidelinesLink}? If you think it does, please tell us more.", "report.CommunityGuidelinesLinkText": "Scratch Community Guidelines", "report.reasonPlaceHolder": "Select a reason", diff --git a/src/redux/session.js b/src/redux/session.js index 8f3ac6bc8..a9886ebfe 100644 --- a/src/redux/session.js +++ b/src/redux/session.js @@ -12,7 +12,7 @@ const Types = keyMirror({ SET_STATUS: null }); -const banWhitelistPaths = [ +const banGoodListPaths = [ '/accounts/banned-response', '/community_guidelines', '/privacy_policy', @@ -68,7 +68,7 @@ const handleSessionResponse = (dispatch, body) => { if ( body.user && body.user.banned && - banWhitelistPaths.indexOf(window.location.pathname) === -1 + banGoodListPaths.every(goodPath => window.location.pathname.indexOf(goodPath) === -1) ) { window.location = '/accounts/banned-response/'; return; diff --git a/src/redux/studio.js b/src/redux/studio.js index bfe677399..29cfb39b1 100644 --- a/src/redux/studio.js +++ b/src/redux/studio.js @@ -91,6 +91,7 @@ const selectStudioDescription = state => state.studio.description; const selectStudioImage = state => state.studio.image; const selectStudioOpenToAll = state => state.studio.openToAll; const selectStudioCommentsAllowed = state => state.studio.commentsAllowed; +const selectStudioLoadFailed = state => state.studio.infoStatus === Status.ERROR; const selectIsFetchingInfo = state => state.studio.infoStatus === Status.FETCHING; const selectIsFollowing = state => state.studio.following; const selectIsFetchingRoles = state => state.studio.rolesStatus === Status.FETCHING; @@ -157,6 +158,7 @@ module.exports = { selectStudioImage, selectStudioOpenToAll, selectStudioCommentsAllowed, + selectStudioLoadFailed, selectIsFetchingInfo, selectIsFetchingRoles, selectIsFollowing diff --git a/src/views/developers/developers.jsx b/src/views/developers/developers.jsx index 858fde3cb..bf99abf1c 100644 --- a/src/views/developers/developers.jsx +++ b/src/views/developers/developers.jsx @@ -363,9 +363,9 @@ const Developers = () => ( githubLink: ( GitHub ), - emailLink: ( - - help@scratch.mit.edu + contactUsLink: ( + + ) }} diff --git a/src/views/developers/l10n.json b/src/views/developers/l10n.json index fd8c0604c..e2f5b18bc 100644 --- a/src/views/developers/l10n.json +++ b/src/views/developers/l10n.json @@ -56,5 +56,5 @@ "developers.faqDifferencesTitle": "What’s the difference between Blockly and Scratch Blocks?", "developers.faqDifferencesBody": "Scratch Blocks builds upon the Blockly code base, and is specifically designed with our principles in mind to support creative learning experiences.", "developers.faqCollabTitle": "I’d like to collaborate. How do I get in touch?", - "developers.faqCollabBody": "You can reach us over on {githubLink} or you can send an email to {emailLink}. We look forward to hearing from you!" + "developers.faqCollabBody": "You can reach us over on {githubLink} or on our {contactUsLink} page. We look forward to hearing from you!" } diff --git a/src/views/join/join.jsx b/src/views/join/join.jsx index d51659939..2a6cda393 100644 --- a/src/views/join/join.jsx +++ b/src/views/join/join.jsx @@ -2,8 +2,6 @@ const React = require('react'); const render = require('../../lib/render.jsx'); const Scratch3Registration = require('../../components/registration/scratch3-registration.jsx'); const ErrorBoundary = require('../../components/errorboundary/errorboundary.jsx'); -// Require this even though we don't use it because, without it, webpack runs out of memory... -const Page = require('../../components/page/www/page.jsx'); // eslint-disable-line no-unused-vars const initSentry = require('../../lib/sentry.js'); initSentry(); diff --git a/src/views/splash/donate/donate-banner.jsx b/src/views/splash/donate/donate-banner.jsx new file mode 100644 index 000000000..236387f30 --- /dev/null +++ b/src/views/splash/donate/donate-banner.jsx @@ -0,0 +1,56 @@ +const FormattedMessage = require('react-intl').FormattedMessage; +const injectIntl = require('react-intl').injectIntl; +const PropTypes = require('prop-types'); +const React = require('react'); + +const TitleBanner = require('../../../components/title-banner/title-banner.jsx'); +const Button = require('../../../components/forms/button.jsx'); + +require('./donate-banner.scss'); + +const navigateToDonatePage = () => { + window.location = 'https://secure.donationpay.org/scratchfoundation'; +}; + +const DonateTopBanner = ({ + onRequestClose +}) => ( + +
+ +
+

+ +

+ +
+
+ +
+); + +DonateTopBanner.propTypes = { + onRequestClose: PropTypes.func +}; + +module.exports = injectIntl(DonateTopBanner); diff --git a/src/views/splash/donate/donate-banner.scss b/src/views/splash/donate/donate-banner.scss new file mode 100644 index 000000000..522baf875 --- /dev/null +++ b/src/views/splash/donate/donate-banner.scss @@ -0,0 +1,77 @@ +@import "../../../colors"; +@import "../../../frameless"; + +$tile-height: 244px; + +.donate-banner { + display: flex; + position: fixed; + z-index: 8; + background-color: $ui-aqua-dark; + padding: 0; + overflow: hidden; + align-items: center; + justify-content: center; + + .donate-container { + display: flex; + margin: 0.375rem auto; + align-items: center; + + .donate-icon { + margin: 0.6875rem; + width: 1.75rem; + height: 1.75rem; + } + + .donate-central-items { + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + } + + .donate-text { + text-align: left; + color: $ui-white; + font-size: 1rem; + font-weight: bold; + margin-right: 1rem; + max-width: 70vw; + } + + .donate-button { + margin: 0 7rem 0 .5rem; + border-radius: 1.25rem; + background-color: $ui-white; + color: $ui-aqua-dark; + padding: 0 1.75rem; + height: 2.25rem; + text-decoration: none; + line-height: .875rem; + font-size: 1rem; + font-weight: bold; + } + } + + .donate-close-button { + right: 1rem; + top: auto; + } +} + +@media only screen and (max-width: $mobileIntermediate) { + .donate-banner .donate-container .donate-central-items { + flex-wrap: wrap; + } + .donate-banner .donate-container .donate-icon { + padding-bottom: 2rem; + } + .donate-banner .donate-container .donate-button { + margin-left: 0; + margin-bottom: 1rem + } + .donate-banner .donate-close-button { + top: 1rem; + } +} diff --git a/src/views/splash/l10n.json b/src/views/splash/l10n.json index fd4db0e38..3927ecb24 100644 --- a/src/views/splash/l10n.json +++ b/src/views/splash/l10n.json @@ -29,6 +29,8 @@ "intro.watchVideo": "Watch Video", "news.scratchNews": "Scratch News", + "donatebanner.askSupport": "Scratch is the world's largest free coding community for kids. Your support makes a difference.", + "teacherbanner.greeting": "Hi", "teacherbanner.subgreeting": "Teacher Account", "teacherbanner.classesButton": "My Classes", diff --git a/src/views/splash/presentation.jsx b/src/views/splash/presentation.jsx index ed28fdd9f..b65dde823 100644 --- a/src/views/splash/presentation.jsx +++ b/src/views/splash/presentation.jsx @@ -32,12 +32,10 @@ const LoveProjectMessage = require('./activity-rows/love-project.jsx'); const RemixProjectMessage = require('./activity-rows/remix-project.jsx'); const ShareProjectMessage = require('./activity-rows/share-project.jsx'); -// Hour of Code Banner Components -const TopBanner = require('./hoc/top-banner.jsx'); -const MiddleBanner = require('./hoc/middle-banner.jsx'); - -const HOC_START_TIME = 1605484800000; // 2020-11-16 00:00:00 -const HOC_END_TIME = 1608681600000; // 2020-12-23 00:00:00 +// Banner Components +const DonateBanner = require('./donate/donate-banner.jsx'); +const HOCTopBanner = require('./hoc/top-banner.jsx'); +const HOCMiddleBanner = require('./hoc/middle-banner.jsx'); require('./splash.scss'); @@ -352,6 +350,7 @@ class SplashPresentation extends React.Component { // eslint-disable-line react/ const formatHTMLMessage = this.props.intl.formatHTMLMessage; const formatMessage = this.props.intl.formatMessage; + const messages = { 'general.viewAll': formatMessage({id: 'general.viewAll'}), 'news.scratchNews': formatMessage({id: 'news.scratchNews'}), @@ -412,21 +411,28 @@ class SplashPresentation extends React.Component { // eslint-disable-line react/ /> ] : []} { - this.props.sessionStatus === sessionActions.Status.FETCHED && - Object.keys(this.props.user).length === 0 && (// Only show top banner if user is not logged in - (Date.now() >= HOC_START_TIME && Date.now() < HOC_END_TIME) ? ( - - - - ) : ( - - ) + this.props.shouldShowHOCTopBanner && ( + + + + ) + } + { + this.props.shouldShowDonateBanner && ( + + ) + } + { + this.props.shouldShowIntro && ( + ) }
{ - this.props.sessionStatus === sessionActions.Status.FETCHED && - Object.keys(this.props.user).length !== 0 && // Only show if user is logged in - Date.now() >= HOC_START_TIME && // Show middle banner on and after Dec 3 - Date.now() < HOC_END_TIME && // Hide middle banner after Dec 14 - false && // we did not use this middle banner in last HoC - - - + this.props.shouldShowHOCMiddleBanner && ( + + + + ) }
= HOC_START_TIME && + Date.now() < HOC_END_TIME + ); + } + shouldShowHOCMiddleBanner () { + return false; // we did not use this middle banner in last HoC + } + shouldShowDonateBanner () { + return ( + this.state.dismissedDonateBanner === false && + this.props.sessionStatus === sessionActions.Status.FETCHED && // done fetching session + Object.keys(this.props.user).length === 0 && // no user session found + Date.now() >= SCRATCH_WEEK_START_TIME && + Date.now() < SCRATCH_WEEK_END_TIME && + this.shouldShowHOCTopBanner() !== true + ); + } render () { const showEmailConfirmation = this.shouldShowEmailConfirmation() || false; + const showDonateBanner = this.shouldShowDonateBanner() || false; + const showHOCTopBanner = this.shouldShowHOCTopBanner() || false; + const showHOCMiddleBanner = this.shouldShowHOCMiddleBanner() || false; + const showIntro = showHOCTopBanner !== true; const showWelcome = this.shouldShowWelcome(); const homepageRefreshStatus = this.getHomepageRefreshStatus(); @@ -163,9 +198,14 @@ class Splash extends React.Component { refreshCacheStatus={homepageRefreshStatus} sessionStatus={this.props.sessionStatus} sharedByFollowing={this.props.shared} + shouldShowDonateBanner={showDonateBanner} shouldShowEmailConfirmation={showEmailConfirmation} + shouldShowHOCTopBanner={showHOCTopBanner} + shouldShowIntro={showIntro} + shouldShowHOCMiddleBanner={showHOCMiddleBanner} shouldShowWelcome={showWelcome} user={this.props.user} + onCloseDonateBanner={this.handleCloseDonateBanner} onCloseAdminPanel={this.handleCloseAdminPanel} onDismiss={this.handleDismiss} onHideEmailConfirmationModal={this.handleHideEmailConfirmationModal} diff --git a/src/views/studio/l10n.json b/src/views/studio/l10n.json new file mode 100644 index 000000000..746cc5377 --- /dev/null +++ b/src/views/studio/l10n.json @@ -0,0 +1,28 @@ +{ + "studio.tabNavProjects": "Projects", + "studio.tabNavCurators": "Curators", + "studio.tabNavComments": "Comments", + "studio.tabNavActivity": "Activity", + + "studio.title": "Title", + "studio.description": "Description", + "studio.thumbnail": "Thumbnail", + + "studio.projectsHeader": "Projects", + "studio.addProjectsHeader": "Add Projects", + "studio.addProject": "Add", + + "studio.creatorRole": "Studio Creator", + + "studio.managersHeader": "Managers", + + "studio.unfollowStudio": "Unfollow Studio", + "studio.followStudio": "Follow Studio", + + "studio.curatorsHeader": "Curators", + "studio.inviteCuratorsHeader": "Invite Curators", + "studio.inviteCurator": "Invite", + "studio.curatorAcceptInvite": "Accept Invite", + + "studio.commentsHeader": "Comments" +} \ No newline at end of file diff --git a/src/views/studio/studio-comments.jsx b/src/views/studio/studio-comments.jsx index 2cd1495dd..7e0b020e7 100644 --- a/src/views/studio/studio-comments.jsx +++ b/src/views/studio/studio-comments.jsx @@ -56,7 +56,7 @@ const StudioComments = ({ return (
-

Comments

+

{canEditCommentsAllowed && }
{shouldShowCommentComposer && commentsAllowed && diff --git a/src/views/studio/studio-curator-invite.jsx b/src/views/studio/studio-curator-invite.jsx index d3568555b..7fe1a129a 100644 --- a/src/views/studio/studio-curator-invite.jsx +++ b/src/views/studio/studio-curator-invite.jsx @@ -3,6 +3,7 @@ import React, {useState} from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; import classNames from 'classnames'; +import {FormattedMessage} from 'react-intl'; import {acceptInvitation} from './lib/studio-member-actions'; @@ -26,7 +27,7 @@ const StudioCuratorInvite = ({onSubmit}) => { setSubmitting(false); }); }} - >Accept invite + > {error &&
{error}
}
); diff --git a/src/views/studio/studio-curator-inviter.jsx b/src/views/studio/studio-curator-inviter.jsx index 17d81622d..d7baa4bed 100644 --- a/src/views/studio/studio-curator-inviter.jsx +++ b/src/views/studio/studio-curator-inviter.jsx @@ -3,6 +3,7 @@ import React, {useState} from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; import classNames from 'classnames'; +import {FormattedMessage} from 'react-intl'; import {inviteCurator} from './lib/studio-member-actions'; @@ -20,7 +21,7 @@ const StudioCuratorInviter = ({onSubmit}) => { }; return (
-

✦ Invite Curators

+

{ })} disabled={submitting} onClick={submit} - >Invite + > {error &&
{error}
}
); diff --git a/src/views/studio/studio-curators.jsx b/src/views/studio/studio-curators.jsx index cddb42851..adffbb989 100644 --- a/src/views/studio/studio-curators.jsx +++ b/src/views/studio/studio-curators.jsx @@ -1,6 +1,7 @@ import React, {useEffect} from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; +import {FormattedMessage} from 'react-intl'; import {curators} from './lib/redux-modules'; import Debug from './debug.jsx'; @@ -18,7 +19,7 @@ const StudioCurators = ({ }, []); return (
-

Curators

+

{canInviteCurators && } {showCuratorInvite && } {error && Loading... : ( moreToLoad ? : No more to load )} diff --git a/src/views/studio/studio-follow.jsx b/src/views/studio/studio-follow.jsx index b20feac96..5e3a51b9a 100644 --- a/src/views/studio/studio-follow.jsx +++ b/src/views/studio/studio-follow.jsx @@ -2,6 +2,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; +import {FormattedMessage} from 'react-intl'; + import {selectIsFollowing} from '../../redux/studio'; import {selectCanFollowStudio} from '../../redux/studio-permissions'; import { @@ -28,7 +30,9 @@ const StudioFollow = ({ onClick={() => handleFollow(!isFollowing)} > {isMutating ? '...' : ( - isFollowing ? 'Unfollow Studio' : 'Follow Studio' + isFollowing ? + : + )} {followingError &&
Error mutating following: {followingError}
} diff --git a/src/views/studio/studio-managers.jsx b/src/views/studio/studio-managers.jsx index ffb750a97..e934df55d 100644 --- a/src/views/studio/studio-managers.jsx +++ b/src/views/studio/studio-managers.jsx @@ -1,6 +1,7 @@ import React, {useEffect} from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; +import {FormattedMessage} from 'react-intl'; import {managers} from './lib/redux-modules'; import {loadManagers} from './lib/studio-member-actions'; @@ -15,7 +16,7 @@ const StudioManagers = ({items, error, loading, moreToLoad, onLoadMore}) => { return (
-

Managers

+

{error && { {loading ? Loading... : ( moreToLoad ? : No more to load )} diff --git a/src/views/studio/studio-member-tile.jsx b/src/views/studio/studio-member-tile.jsx index a6736b973..208316dfc 100644 --- a/src/views/studio/studio-member-tile.jsx +++ b/src/views/studio/studio-member-tile.jsx @@ -3,6 +3,7 @@ import React, {useState} from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; import classNames from 'classnames'; +import {FormattedMessage} from 'react-intl'; import { selectCanRemoveCurators, selectCanRemoveManager, selectCanPromoteCurators @@ -33,7 +34,7 @@ const StudioMemberTile = ({ href={userUrl} className="studio-member-name" >{username} - {isCreator &&
Studio Creator
} + {isCreator &&
}
{canRemove && + > {error &&
{error}
}
); diff --git a/src/views/studio/studio-projects.jsx b/src/views/studio/studio-projects.jsx index db9c62e2a..def04e13b 100644 --- a/src/views/studio/studio-projects.jsx +++ b/src/views/studio/studio-projects.jsx @@ -2,6 +2,7 @@ import React, {useEffect} from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; import StudioOpenToAll from './studio-open-to-all.jsx'; +import {FormattedMessage} from 'react-intl'; import {projects} from './lib/redux-modules'; import {selectCanAddProjects, selectCanEditOpenToAll} from '../../redux/studio-permissions'; @@ -19,7 +20,7 @@ const StudioProjects = ({ return (
-

Projects

+

{canEditOpenToAll && } {canAddProjects && } {error && Loading... : ( moreToLoad ? : No more to load )} diff --git a/src/views/studio/studio-report.jsx b/src/views/studio/studio-report.jsx index 984fa5d0b..bf8c91416 100644 --- a/src/views/studio/studio-report.jsx +++ b/src/views/studio/studio-report.jsx @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; +import {FormattedMessage} from 'react-intl'; import { Fields, @@ -24,15 +25,15 @@ const StudioReport = ({

Reporting

{canReport && ( - + )} {isOpen && (
-
Report Studio Modal
+
{previouslyReported ? (
Submitted the report!
- +
) : ( @@ -40,9 +41,9 @@ const StudioReport = ({ value={field} onChange={e => handleSetField(e.target.value)} > - - - + + + {error && (
@@ -54,9 +55,9 @@ const StudioReport = ({ disabled={isSubmitting} onClick={handleSubmit} > - Submit + - + )}
diff --git a/src/views/studio/studio-tab-nav.jsx b/src/views/studio/studio-tab-nav.jsx index 0ae69d82c..a6ea0fdd6 100644 --- a/src/views/studio/studio-tab-nav.jsx +++ b/src/views/studio/studio-tab-nav.jsx @@ -1,6 +1,7 @@ import React from 'react'; import {useRouteMatch, NavLink} from 'react-router-dom'; import SubNavigation from '../../components/subnavigation/subnavigation.jsx'; +import {FormattedMessage} from 'react-intl'; const StudioTabNav = () => { const {params: {studioPath, studioId}} = useRouteMatch(); @@ -15,25 +16,25 @@ const StudioTabNav = () => { to={base} exact > -
  • Projects
  • +
  • -
  • Comments
  • +
  • -
  • Curators
  • +
  • -
  • Activity
  • +
  • ); diff --git a/src/views/studio/studio.jsx b/src/views/studio/studio.jsx index 001fc3655..37ebb9517 100644 --- a/src/views/studio/studio.jsx +++ b/src/views/studio/studio.jsx @@ -6,9 +6,14 @@ import { Redirect, useRouteMatch } from 'react-router-dom'; +import PropTypes from 'prop-types'; +import {connect} from 'react-redux'; + import Page from '../../components/page/www/page.jsx'; import render from '../../lib/render.jsx'; +import NotAvailable from '../../components/not-available/not-available.jsx'; + import StudioTabNav from './studio-tab-nav.jsx'; import StudioProjects from './studio-projects.jsx'; @@ -25,56 +30,68 @@ import { activity } from './lib/redux-modules'; -const {getInitialState, studioReducer} = require('../../redux/studio'); +const {getInitialState, studioReducer, selectStudioLoadFailed} = require('../../redux/studio'); const {studioReportReducer} = require('../../redux/studio-report'); const {commentsReducer} = require('../../redux/comments'); const {studioMutationsReducer} = require('../../redux/studio-mutations'); import './studio.scss'; -const StudioShell = () => { +const StudioShell = ({studioLoadFailed}) => { const match = useRouteMatch(); return ( -
    -
    - -
    -
    - -
    - - - - - - - - - - - - - {/* We can force /projects back to / this way */} - - - - - - + studioLoadFailed ? + : +
    +
    + +
    +
    + +
    + + + + + + + + + + + + + {/* We can force /projects back to / this way */} + + + + + + +
    -
    ); }; +StudioShell.propTypes = { + studioLoadFailed: PropTypes.bool +}; + +const ConnectedStudioShell = connect( + state => ({ + studioLoadFailed: selectStudioLoadFailed(state) + }), +)(StudioShell); + render( {/* Use variable studioPath to support /studio-playground/ or future route */} - + diff --git a/src/views/teachers/faq/faq.jsx b/src/views/teachers/faq/faq.jsx index fcab5e6cb..c0ab66f09 100644 --- a/src/views/teachers/faq/faq.jsx +++ b/src/views/teachers/faq/faq.jsx @@ -50,25 +50,6 @@ const TeacherFaq = props => (
    -
    -
    - - help@scratch.mit.edu - - ) - }} - /> -
    -
      -
    • -
    • -
    • -
    -
    diff --git a/src/views/teachers/faq/l10n.json b/src/views/teachers/faq/l10n.json index 39f26ead2..3aee57b4b 100644 --- a/src/views/teachers/faq/l10n.json +++ b/src/views/teachers/faq/l10n.json @@ -10,11 +10,6 @@ "teacherfaq.teacherSignUpBody": "To request a Teacher Account, please go to the teacher account request form.", "teacherfaq.classMultipleTeachersTitle": "Can a class have multiple teachers?", "teacherfaq.classMultipleTeachersBody": "A class can only have one teacher account associated with it.", - "teacherfaq.convertToTeacherTitle": "I already have a Scratch account, can you make it a Teacher account?", - "teacherfaq.convertToTeacherList": "Please send an email to {helpEmail} and be sure to include the following information:", - "teacherfaq.convertToTeacherUsername": "Your Scratch username (Please double check that you know your username by logging into it before contacting us!)", - "teacherfaq.convertToTeacherEmail": "The email address associated with your Scratch account", - "teacherfaq.convertToTeacherBirth": "The birth month and birth year associated with your Scratch account", "teacherfaq.teacherPersonalTitle": "Why do you need to know my personal information during registration?", "teacherfaq.teacherPersonalBody": "We use this information to verify the account creator is an educator. We will not share this information with anyone else, and it will not be shared publicly on the site.", "teacherfaq.teacherGoogleTitle": "Does Scratch connect with Google Classroom, Clever or any other classroom management service?",