diff --git a/package-lock.json b/package-lock.json index b005f996e..67ba0d76f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "react-twitter-embed": "^3.0.3", "react-use": "^17.3.1", "scratch-parser": "5.1.1", - "scratch-storage": "2.2.0" + "scratch-storage": "2.2.1" }, "devDependencies": { "@formatjs/intl-datetimeformat": "6.4.3", @@ -101,8 +101,8 @@ "regenerator-runtime": "0.13.9", "sass": "1.49.7", "sass-loader": "10.2.1", - "scratch-gui": "1.8.0", - "scratch-l10n": "3.15.20230327032134", + "scratch-gui": "1.8.21", + "scratch-l10n": "3.15.20230412032123", "selenium-webdriver": "4.1.0", "slick-carousel": "1.6.0", "style-loader": "0.12.3", @@ -23463,21 +23463,21 @@ } }, "node_modules/scratch-blocks": { - "version": "0.1.0-prerelease.20230326090609", - "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20230326090609.tgz", - "integrity": "sha512-xzUHK3P98uUlwZonIW/kz9KYMxwvGpwocT8t/QFXEUsQpGIWuVMVDD8GiyKmtPN4ZhtNd/BjQSpa+Uv9wRwmcg==", + "version": "0.1.0-prerelease.20230412165437", + "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20230412165437.tgz", + "integrity": "sha512-sxdCHrKPUnQyigL8EX20AsztjOitVo5ruQCwUNwLQeCVS1HaBWo3LyE2E6E6QMsnPsS81Z5UeqM5z+9W2hjyeQ==", "dev": true, "dependencies": { "exports-loader": "0.7.0", "google-closure-library": "20190301.0.0", "imports-loader": "0.8.0", - "scratch-l10n": "3.15.20230326032128" + "scratch-l10n": "3.15.20230410032122" } }, "node_modules/scratch-blocks/node_modules/scratch-l10n": { - "version": "3.15.20230326032128", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230326032128.tgz", - "integrity": "sha512-eGs59KH1J+K+e1QW1fU3kudoW1GGboT7cdJoXoT5O524WSvnl2SwSaEYI1jt3mO03Za7fMy2OYTlx4W2x7UcKQ==", + "version": "3.15.20230410032122", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230410032122.tgz", + "integrity": "sha512-XUJZIG9GAh5ePB+xszRpdzqAD3nPaAxNwOdM+bnxALq/2rk9mieFF4/6vaE3+t8Yigbt0/CPsy5Y2weLTrKVOQ==", "dev": true, "dependencies": { "@babel/cli": "^7.1.2", @@ -23493,9 +23493,9 @@ } }, "node_modules/scratch-gui": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-1.8.0.tgz", - "integrity": "sha512-FFyUEBGVVO8yKZcp/tv8kn5/C9tVhbimK+WvUkTYrswZ3HLz8mqpgXmM7shYKwb03pqv1uxpU/XwiU9OSur5Yw==", + "version": "1.8.21", + "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-1.8.21.tgz", + "integrity": "sha512-/XF1V1zt9D3EDw1Po6WIRXEDunbatHoK4hDoRJN+VMh0F+4MCCBsmdNOUecsESAp6H4NeAWv5iXxfInpCU8WWg==", "dev": true, "dependencies": { "arraybuffer-loader": "^1.0.6", @@ -23547,14 +23547,14 @@ "redux": "3.7.2", "redux-throttle": "0.1.1", "scratch-audio": "0.1.0-prerelease.20221123180128", - "scratch-blocks": "0.1.0-prerelease.20230326090609", - "scratch-l10n": "3.15.20230326032128", - "scratch-paint": "1.1.38", + "scratch-blocks": "0.1.0-prerelease.20230412165437", + "scratch-l10n": "3.15.20230412032123", + "scratch-paint": "1.1.46", "scratch-render": "0.1.0-prerelease.20230318150639", "scratch-render-fonts": "1.0.0-prerelease.20221102164332", - "scratch-storage": "2.2.0", + "scratch-storage": "2.2.1", "scratch-svg-renderer": "0.2.0-prerelease.20230224194137", - "scratch-vm": "1.5.10", + "scratch-vm": "1.5.29", "startaudiocontext": "1.2.1", "style-loader": "^0.23.0", "text-encoding": "0.7.0", @@ -23880,28 +23880,10 @@ "symbol-observable": "^1.0.3" } }, - "node_modules/scratch-gui/node_modules/scratch-l10n": { - "version": "3.15.20230326032128", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230326032128.tgz", - "integrity": "sha512-eGs59KH1J+K+e1QW1fU3kudoW1GGboT7cdJoXoT5O524WSvnl2SwSaEYI1jt3mO03Za7fMy2OYTlx4W2x7UcKQ==", - "dev": true, - "dependencies": { - "@babel/cli": "^7.1.2", - "@babel/core": "^7.1.2", - "@transifex/api": "4.2.5", - "babel-plugin-react-intl": "^3.0.1", - "download": "^8.0.0", - "transifex": "1.6.6" - }, - "bin": { - "build-i18n-src": "scripts/build-i18n-src.js", - "tx-push-src": "scripts/tx-push-src.js" - } - }, "node_modules/scratch-gui/node_modules/scratch-paint": { - "version": "1.1.38", - "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-1.1.38.tgz", - "integrity": "sha512-fB/ltIMqkIWq68LtzhES+RxaK8eetwwOU2ZsuPab5Ggy624lqpK6LHIPgr55FS8AGM5NNC9nD5jQVbdZ7EBzPQ==", + "version": "1.1.46", + "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-1.1.46.tgz", + "integrity": "sha512-uklJlBvb9dGt1A50kEp1TZ3hWS1dZWWoL7+l7gIR6eILSglmcO0iqPCfDoy9lB4AybaMIDs9goDOqmq+mAZ2Sg==", "dev": true, "dependencies": { "@scratch/paper": "0.11.20200728195508", @@ -23980,9 +23962,9 @@ } }, "node_modules/scratch-l10n": { - "version": "3.15.20230327032134", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230327032134.tgz", - "integrity": "sha512-5Y5F+vXEqz1GVqJ2IRsQCjyrJV7f99akFSIwfXBdSfty1h8KUP9K+RhDz8zZaXzeZq/SlMLM0LMsrG0KQSyTuA==", + "version": "3.15.20230412032123", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230412032123.tgz", + "integrity": "sha512-k0X6Xf0u7CBUMMvzryhlcpL96Lhqx4qkot7A6gyLcOJ6WmfmfeM/xHvThA5AI3QT7tB2HMBeAKUx/ST4p2z5eg==", "dev": true, "dependencies": { "@babel/cli": "^7.1.2", @@ -24111,9 +24093,9 @@ } }, "node_modules/scratch-storage": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/scratch-storage/-/scratch-storage-2.2.0.tgz", - "integrity": "sha512-d2DzApJ9cSlQ42/cEKDD/lfYIocHMskWrOQ5VED6tKgiHirjRZSPflUIfWL8lY5LxE3HSBc/Z7pS3Yvqe/iCGA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/scratch-storage/-/scratch-storage-2.2.1.tgz", + "integrity": "sha512-qogGcWBXqKUHgfvSgyUkos4fuj7z+SDDHBVlT3NNC4gtZgw4dq+USwHjKXCwtRs6BN/joI7+LafFJtSLii6G/w==", "dependencies": { "@babel/runtime": "7.21.0", "arraybuffer-loader": "^1.0.3", @@ -24182,9 +24164,9 @@ "dev": true }, "node_modules/scratch-vm": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-1.5.10.tgz", - "integrity": "sha512-XHRxoTBWKIBymLqcelAeYdIJz6i7t/Av6Z7nOH1nCHourR1mvNs23Xk7ospFu9LVDTtLGVq9LkKgckqsG8SKuA==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-1.5.29.tgz", + "integrity": "sha512-vTDTPa8meaa8Nnz2VxA9rsQ6+avIcDVKQLTJocTxXy0C+ucrQkXBqpzSf5nObqwWSDKsZEpD4TtcReIx8b6BvQ==", "dev": true, "dependencies": { "@vernier/godirect": "1.5.0", @@ -51963,21 +51945,21 @@ } }, "scratch-blocks": { - "version": "0.1.0-prerelease.20230326090609", - "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20230326090609.tgz", - "integrity": "sha512-xzUHK3P98uUlwZonIW/kz9KYMxwvGpwocT8t/QFXEUsQpGIWuVMVDD8GiyKmtPN4ZhtNd/BjQSpa+Uv9wRwmcg==", + "version": "0.1.0-prerelease.20230412165437", + "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20230412165437.tgz", + "integrity": "sha512-sxdCHrKPUnQyigL8EX20AsztjOitVo5ruQCwUNwLQeCVS1HaBWo3LyE2E6E6QMsnPsS81Z5UeqM5z+9W2hjyeQ==", "dev": true, "requires": { "exports-loader": "0.7.0", "google-closure-library": "20190301.0.0", "imports-loader": "0.8.0", - "scratch-l10n": "3.15.20230326032128" + "scratch-l10n": "3.15.20230410032122" }, "dependencies": { "scratch-l10n": { - "version": "3.15.20230326032128", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230326032128.tgz", - "integrity": "sha512-eGs59KH1J+K+e1QW1fU3kudoW1GGboT7cdJoXoT5O524WSvnl2SwSaEYI1jt3mO03Za7fMy2OYTlx4W2x7UcKQ==", + "version": "3.15.20230410032122", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230410032122.tgz", + "integrity": "sha512-XUJZIG9GAh5ePB+xszRpdzqAD3nPaAxNwOdM+bnxALq/2rk9mieFF4/6vaE3+t8Yigbt0/CPsy5Y2weLTrKVOQ==", "dev": true, "requires": { "@babel/cli": "^7.1.2", @@ -51991,9 +51973,9 @@ } }, "scratch-gui": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-1.8.0.tgz", - "integrity": "sha512-FFyUEBGVVO8yKZcp/tv8kn5/C9tVhbimK+WvUkTYrswZ3HLz8mqpgXmM7shYKwb03pqv1uxpU/XwiU9OSur5Yw==", + "version": "1.8.21", + "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-1.8.21.tgz", + "integrity": "sha512-/XF1V1zt9D3EDw1Po6WIRXEDunbatHoK4hDoRJN+VMh0F+4MCCBsmdNOUecsESAp6H4NeAWv5iXxfInpCU8WWg==", "dev": true, "requires": { "arraybuffer-loader": "^1.0.6", @@ -52045,14 +52027,14 @@ "redux": "3.7.2", "redux-throttle": "0.1.1", "scratch-audio": "0.1.0-prerelease.20221123180128", - "scratch-blocks": "0.1.0-prerelease.20230326090609", - "scratch-l10n": "3.15.20230326032128", - "scratch-paint": "1.1.38", + "scratch-blocks": "0.1.0-prerelease.20230412165437", + "scratch-l10n": "3.15.20230412032123", + "scratch-paint": "1.1.46", "scratch-render": "0.1.0-prerelease.20230318150639", "scratch-render-fonts": "1.0.0-prerelease.20221102164332", - "scratch-storage": "2.2.0", + "scratch-storage": "2.2.1", "scratch-svg-renderer": "0.2.0-prerelease.20230224194137", - "scratch-vm": "1.5.10", + "scratch-vm": "1.5.29", "startaudiocontext": "1.2.1", "style-loader": "^0.23.0", "text-encoding": "0.7.0", @@ -52316,24 +52298,10 @@ "symbol-observable": "^1.0.3" } }, - "scratch-l10n": { - "version": "3.15.20230326032128", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230326032128.tgz", - "integrity": "sha512-eGs59KH1J+K+e1QW1fU3kudoW1GGboT7cdJoXoT5O524WSvnl2SwSaEYI1jt3mO03Za7fMy2OYTlx4W2x7UcKQ==", - "dev": true, - "requires": { - "@babel/cli": "^7.1.2", - "@babel/core": "^7.1.2", - "@transifex/api": "4.2.5", - "babel-plugin-react-intl": "^3.0.1", - "download": "^8.0.0", - "transifex": "1.6.6" - } - }, "scratch-paint": { - "version": "1.1.38", - "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-1.1.38.tgz", - "integrity": "sha512-fB/ltIMqkIWq68LtzhES+RxaK8eetwwOU2ZsuPab5Ggy624lqpK6LHIPgr55FS8AGM5NNC9nD5jQVbdZ7EBzPQ==", + "version": "1.1.46", + "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-1.1.46.tgz", + "integrity": "sha512-uklJlBvb9dGt1A50kEp1TZ3hWS1dZWWoL7+l7gIR6eILSglmcO0iqPCfDoy9lB4AybaMIDs9goDOqmq+mAZ2Sg==", "dev": true, "requires": { "@scratch/paper": "0.11.20200728195508", @@ -52394,9 +52362,9 @@ } }, "scratch-l10n": { - "version": "3.15.20230327032134", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230327032134.tgz", - "integrity": "sha512-5Y5F+vXEqz1GVqJ2IRsQCjyrJV7f99akFSIwfXBdSfty1h8KUP9K+RhDz8zZaXzeZq/SlMLM0LMsrG0KQSyTuA==", + "version": "3.15.20230412032123", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230412032123.tgz", + "integrity": "sha512-k0X6Xf0u7CBUMMvzryhlcpL96Lhqx4qkot7A6gyLcOJ6WmfmfeM/xHvThA5AI3QT7tB2HMBeAKUx/ST4p2z5eg==", "dev": true, "requires": { "@babel/cli": "^7.1.2", @@ -52521,9 +52489,9 @@ } }, "scratch-storage": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/scratch-storage/-/scratch-storage-2.2.0.tgz", - "integrity": "sha512-d2DzApJ9cSlQ42/cEKDD/lfYIocHMskWrOQ5VED6tKgiHirjRZSPflUIfWL8lY5LxE3HSBc/Z7pS3Yvqe/iCGA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/scratch-storage/-/scratch-storage-2.2.1.tgz", + "integrity": "sha512-qogGcWBXqKUHgfvSgyUkos4fuj7z+SDDHBVlT3NNC4gtZgw4dq+USwHjKXCwtRs6BN/joI7+LafFJtSLii6G/w==", "requires": { "@babel/runtime": "7.21.0", "arraybuffer-loader": "^1.0.3", @@ -52593,9 +52561,9 @@ "dev": true }, "scratch-vm": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-1.5.10.tgz", - "integrity": "sha512-XHRxoTBWKIBymLqcelAeYdIJz6i7t/Av6Z7nOH1nCHourR1mvNs23Xk7ospFu9LVDTtLGVq9LkKgckqsG8SKuA==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-1.5.29.tgz", + "integrity": "sha512-vTDTPa8meaa8Nnz2VxA9rsQ6+avIcDVKQLTJocTxXy0C+ucrQkXBqpzSf5nObqwWSDKsZEpD4TtcReIx8b6BvQ==", "dev": true, "requires": { "@vernier/godirect": "1.5.0", diff --git a/package.json b/package.json index 6995bf68e..de7f2b41e 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "react-twitter-embed": "^3.0.3", "react-use": "^17.3.1", "scratch-parser": "5.1.1", - "scratch-storage": "2.2.0" + "scratch-storage": "2.2.1" }, "devDependencies": { "@formatjs/intl-datetimeformat": "6.4.3", @@ -136,8 +136,8 @@ "regenerator-runtime": "0.13.9", "sass": "1.49.7", "sass-loader": "10.2.1", - "scratch-gui": "1.8.0", - "scratch-l10n": "3.15.20230327032134", + "scratch-gui": "1.8.21", + "scratch-l10n": "3.15.20230412032123", "selenium-webdriver": "4.1.0", "slick-carousel": "1.6.0", "style-loader": "0.12.3", diff --git a/src/components/modal/ttt/modal.jsx b/src/components/modal/ttt/modal.jsx index 333f8011b..c6b9efd07 100644 --- a/src/components/modal/ttt/modal.jsx +++ b/src/components/modal/ttt/modal.jsx @@ -20,7 +20,8 @@ const TTTModal = props => ( 'cardsUrl', 'guideUrl', 'thumbImage', - 'modalImage' + 'modalImage', + 'modalImageDescription' ] )} > @@ -29,7 +30,7 @@ const TTTModal = props => (
@@ -91,6 +92,7 @@ TTTModal.propTypes = { description: PropTypes.string.isRequired, guideUrl: PropTypes.string.isRequired, modalImage: PropTypes.string.isRequired, + modalImageDescription: PropTypes.string, thumbImage: PropTypes.string.isRequired, title: PropTypes.string.isRequired, tutorialUrl: PropTypes.string.isRequired diff --git a/src/components/subnavigation/subnavigation.jsx b/src/components/subnavigation/subnavigation.jsx index e9d964975..b04ae38cb 100644 --- a/src/components/subnavigation/subnavigation.jsx +++ b/src/components/subnavigation/subnavigation.jsx @@ -20,6 +20,7 @@ const SubNavigation = props => ( 'sub-nav-align-right': props.align === 'right' } )} + role={props.role} > {props.children}
@@ -27,6 +28,7 @@ const SubNavigation = props => ( SubNavigation.propTypes = { align: PropTypes.string, + role: PropTypes.string, children: PropTypes.node, className: PropTypes.string }; diff --git a/src/components/tabs/tabs.jsx b/src/components/tabs/tabs.jsx index cc637ff56..07553ef13 100644 --- a/src/components/tabs/tabs.jsx +++ b/src/components/tabs/tabs.jsx @@ -1,5 +1,5 @@ -const classNames = require('classnames'); const PropTypes = require('prop-types'); +const {useRef} = require('react'); const React = require('react'); const SubNavigation = require('../../components/subnavigation/subnavigation.jsx'); @@ -10,17 +10,94 @@ require('./tabs.scss'); * Container for a custom, horizontal list of navigation elements * that can be displayed within a view or component. */ -const Tabs = props => ( -
- - {props.children} - -
-); +const Tabs = ({items, activeTabName}) => { + const tabElementRefs = useRef({}); + + const itemsRendered = items.map(({name, onTrigger, getContent}) => { + const isActive = name === activeTabName; + + let tabRef; + if (tabElementRefs.current[name]) { + tabRef = tabElementRefs.current[name]; + } else { + tabRef = React.createRef(); + tabElementRefs.current[name] = tabRef; + } + + return ( + + ); + }); + + const handleKeyDown = event => { + if (!['ArrowLeft', 'ArrowRight', 'Home', 'End', 'Enter', ' '].includes(event.key)) { + return; + } + event.preventDefault(); + const focusedIndex = Object.values(tabElementRefs.current) + .findIndex(tabElementRef => + document.activeElement === tabElementRef.current + ); + if (event.key === 'ArrowLeft') { + let nextIndex; + if (focusedIndex === 0) { + nextIndex = Object.values(tabElementRefs.current).length - 1; + } else { + nextIndex = focusedIndex - 1; + } + Object.values(tabElementRefs.current)[nextIndex].current.focus(); + } else if (event.key === 'ArrowRight') { + let nextIndex; + if (focusedIndex === Object.values(tabElementRefs.current).length - 1) { + nextIndex = 0; + } else { + nextIndex = focusedIndex + 1; + } + Object.values(tabElementRefs.current)[nextIndex].current.focus(); + } else if (event.key === 'Home') { + Object.values(tabElementRefs.current)[0].current.focus(); + } else if (event.key === 'End') { + const lastTab = Object.values(tabElementRefs.current).length - 1; + Object.values(tabElementRefs.current)[lastTab].current.focus(); + } else if (event.key === 'Enter' || event.key === ' ') { + items[focusedIndex].onTrigger(); + } + }; + + return ( +
+ + {itemsRendered} + +
+ ); +}; Tabs.propTypes = { - children: PropTypes.node, - className: PropTypes.string + items: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string.isRequired, + onTrigger: PropTypes.func.isRequired, + getContent: PropTypes.func.isRequired + }) + ).isRequired, + activeTabName: PropTypes.string.isRequired }; module.exports = Tabs; diff --git a/src/components/tabs/tabs.scss b/src/components/tabs/tabs.scss index a612c3f76..791e9723f 100644 --- a/src/components/tabs/tabs.scss +++ b/src/components/tabs/tabs.scss @@ -14,13 +14,14 @@ justify-content: center; } -.tabs li { +.tabs button { margin: 0; border: 0; border-radius: 0; width: $cols2; text-align: center; color: $header-gray; + background-color: transparent; &.active { border-bottom: 3px solid $ui-aqua; diff --git a/src/components/ttt-tile/ttt-tile.jsx b/src/components/ttt-tile/ttt-tile.jsx index 778730db2..b1461398b 100644 --- a/src/components/ttt-tile/ttt-tile.jsx +++ b/src/components/ttt-tile/ttt-tile.jsx @@ -13,7 +13,7 @@ const TTTTile = props => (
@@ -33,6 +33,7 @@ TTTTile.propTypes = { description: PropTypes.string, onClick: PropTypes.func, thumbImage: PropTypes.string.isRequired, + thumbImageDescription: PropTypes.string, title: PropTypes.string.isRequired }; diff --git a/src/l10n.json b/src/l10n.json index 41ce896c0..82ebe2b4b 100644 --- a/src/l10n.json +++ b/src/l10n.json @@ -74,6 +74,8 @@ "general.download": "Download", "general.password": "Password", "general.press": "Press", + "general.projectsSelected": "Projects Tab Selected", + "general.projectsNotS": "Projects", "general.privacyPolicy": "Privacy Policy", "general.projects": "Projects", "general.profile": "Profile", @@ -91,6 +93,8 @@ "general.startOver": "Start over", "general.statistics": "Statistics", "general.studios": "Studios", + "general.studiosSelected": "Studios Tab Selected", + "general.studiosNotS": "Studios", "general.support": "Resources", "general.ideas": "Ideas", "general.tipsWindow": "Tips Window", @@ -111,13 +115,21 @@ "general.seeAllComments": "See all comments", "general.all": "All", + "general.allSelected": "All Selected", "general.animations": "Animations", + "general.animationsSelected": "Animations Selected", "general.art": "Art", + "general.artSelected": "Art Selected", "general.games": "Games", + "general.gamesSelected": "Games Selected", "general.music": "Music", + "general.musicSelected": "Music Selected", "general.results": "Results", + "general.resultsSelected": "Results Selected", "general.stories": "Stories", + "general.storiesSelected": "Stories Selected", "general.tutorials": "Tutorials", + "general.tutorialsSelected": "Tutorials Selected", "general.teacherAccounts": "Teacher Accounts", diff --git a/src/views/explore/explore.jsx b/src/views/explore/explore.jsx index 4bd84f2f9..7d4e9dd42 100644 --- a/src/views/explore/explore.jsx +++ b/src/views/explore/explore.jsx @@ -26,10 +26,8 @@ class Explore extends React.Component { bindAll(this, [ 'getExploreState', 'handleGetExploreMore', - 'changeItemType', 'handleChangeSortMode', - 'getBubble', - 'getTab' + 'getBubble' ]); this.state = this.getExploreState(); @@ -96,16 +94,7 @@ class Explore extends React.Component { } }); } - changeItemType () { - let newType; - for (const t of this.state.acceptableTypes) { - if (this.state.itemType !== t) { - newType = t; - break; - } - } - window.location = `${window.location.origin}/explore/${newType}/${this.state.tab}/${this.state.mode}`; - } + handleChangeSortMode (name, value) { if (this.state.acceptableModes.indexOf(value) !== -1) { window.location = @@ -124,31 +113,7 @@ class Explore extends React.Component { ); } - getTab (type) { - const classes = classNames({ - active: (this.state.itemType === type) - }); - return ( - -
  • - {this.state.itemType === type ? [ - - ] : [ - - ]} - -
  • -
    - ); - } + render () { return (
    @@ -160,10 +125,63 @@ class Explore extends React.Component {
    - - {this.getTab('projects')} - {this.getTab('studios')} - + { + window.location = `${window.location.origin}/explore/projects/` + + `${this.state.category}/${this.state.mode}`; + }, + getContent: isActive => ( +
    + {isActive ? ( + + ) : ( + + ) + } + +
    + ) + }, + { + name: 'studios', + onTrigger: () => { + window.location = `${window.location.origin}/explore/studios/` + + `${this.state.category}/${this.state.mode}`; + }, + getContent: isActive => ( +
    + {isActive ? ( + + ) : ( + + ) + } + +
    + ) + } + ]} + activeTabName={this.state.itemType} + />
    {this.getBubble('all')} diff --git a/src/views/ideas/ideas.jsx b/src/views/ideas/ideas.jsx index 8680cbdc4..af88e4a15 100644 --- a/src/views/ideas/ideas.jsx +++ b/src/views/ideas/ideas.jsx @@ -48,9 +48,11 @@ class Ideas extends React.Component { const translatedTile = { tutorialUrl: `/projects/editor/?tutorial=${tile.tutorialUrl}`, modalImage: tile.modalImage, + modalImageDescription: this.props.intl.formatMessage({id: tile.modalImageDescription}), description: this.props.intl.formatMessage({id: tile.description}), guideUrl: this.props.intl.formatMessage({id: tile.guideUrl}), thumbImage: tile.thumbImage, + thumbImageDescription: this.props.intl.formatMessage({id: tile.thumbImageDescription}), title: this.props.intl.formatMessage({id: tile.title}), cardsUrl: this.props.intl.formatMessage({id: tile.cardsUrl}) }; @@ -71,13 +73,19 @@ class Ideas extends React.Component {
    - + {this.props.intl.formatMessage({id:

    @@ -91,7 +99,10 @@ class Ideas extends React.Component { className="tips-info-section tips-left" >
    - + {this.props.intl.formatMessage({id:

    @@ -102,7 +113,10 @@ class Ideas extends React.Component {

    @@ -161,13 +175,19 @@ class Ideas extends React.Component { target="_blank" >

    - + {this.props.intl.formatMessage({id:
    @@ -183,6 +203,7 @@ class Ideas extends React.Component { >
    {this.props.intl.formatMessage({id:
    @@ -213,6 +234,7 @@ class Ideas extends React.Component {

    @@ -228,6 +250,7 @@ class Ideas extends React.Component {

    diff --git a/src/views/ideas/l10n.json b/src/views/ideas/l10n.json index 68ac299c0..e105c1dfb 100644 --- a/src/views/ideas/l10n.json +++ b/src/views/ideas/l10n.json @@ -1,28 +1,38 @@ { "ideas.headerMessage": "What will you create?", + "ideas.headerImageDescription": "Outlandish creations from pixelated unicorns to drumbeat waveforms to levitating tacos to buckets of rainbows.", "ideas.headerButtonMessage": "Choose a tutorial", "ideas.gettingStartedTitle": "Getting Started", "ideas.gettingStartedText": "New to Scratch? Try the Getting Started tutorial.", + "ideas.gettingStartedImageDescription": "An illustrated boy plants his flag on top of a freshly painted mountaintop.", "ideas.tryIt": "Try it!", "ideas.activityGuidesTitle": "Activity Guides", "ideas.activityGuidesText": "What do you want to make with Scratch? For each activity, you can try the Tutorial, download a set of Coding Cards, or view the Educator Guide.", "ideas.animateANameTitle": "Animate a Name", "ideas.animateANameDescription": "Animate the letters of your name, initials, or favorite word.", + "ideas.animateANameImageDescription": "The name ANYA in all caps and blocked letters is poised to wiggle", "ideas.animateACharacterTitle": "Animate a Character", "ideas.animateACharacterDescription": "Bring characters to life with animation.", + "ideas.animateACharacterImageDescription": "An taco with a wand, wizard cap and flowing white beard floats enchantingly in low-Earth orbit.", "ideas.makeMusicTitle": "Make Music", "ideas.makeMusicDescription": "Choose instruments, add sounds, and press keys to play music.", + "ideas.makeMusicImageDescription": "Strings vibrate on an illustrated Gibson explorer.", "ideas.createAStoryTitle": "Create a Story", "ideas.createAStoryDescription": "Choose characters, add conversation, and bring your story to life.", + "ideas.createAStoryImageDescription": "A wizard beckons a traveling witch towards a distant castle.", "ideas.chaseGameTitle": "Make a Chase Game", "ideas.chaseGameDescription": "Make a game where you chase a character to score points.", + "ideas.chaseGameImageDescription": "A happy interactive octopus passes over a star.", "ideas.videoSensingTitle": "Video Sensing", "ideas.videoSensingDescription": "Interact with a project using the Video Sensing extension.", + "ideas.videoSensingImageDescription": "A virtual hand dodges a spurt of flame in an attempt to pet a dragon.", "ideas.seeAllTutorials": "See All Tutorials", "ideas.cardsTitle": "Get the Entire Collection of Coding Cards", "ideas.cardsText": "With the Scratch Coding Cards, you can learn to create interactive games, stories, music, animations, and more!", + "ideas.cardsIllustrationDescription": "An assortment of fun, animated characters and objects leap out of a stack of cards.", "ideas.starterProjectsTitle": "Starter Projects", "ideas.starterProjectsText": "You can play with Starter Projects and remix them to make your own creations.", + "ideas.starterProjectsImageDescription": "An illustration of the Scratch Code Editor.", "ideas.starterProjectsButton": "Explore Starter Projects", "ideas.tryTheTutorial": "Try the tutorial", "ideas.codingCards": "Coding Cards", @@ -36,6 +46,7 @@ "ideas.cardsPurchase": "Purchase Printed Set", "ideas.MakeItFlyTitle": "Make It Fly", "ideas.MakeItFlyDescription": "Choose any character and make it fly!", + "ideas.MakeItFlyImageDescription": "The scratch cat flies over the skyline. Alongside a flying taco.", "ideas.RaceTitle": "Race to the Finish", "ideas.RaceDescription": "Make a game where two characters race each other.", "ideas.HideAndSeekTitle": "Hide and Seek", @@ -44,8 +55,10 @@ "ideas.FashionDescription": "Make a game where you dress a character with different clothes and styles.", "ideas.PongTitle": "Pong Game", "ideas.PongDescription": "Make a bouncing ball game with sounds, points, and other effects.", + "ideas.PongImageDescription": "A ball bounces off a digital paddle.", "ideas.ImagineTitle": "Imagine a World", "ideas.ImagineDescription": "Imagine a world where anything is possible.", + "ideas.ImagineImageDescription": "A girl stands proudly in front of a thought bubble as big as the Earth and as intricate as butterfly wings.", "ideas.DanceTitle": "Let's Dance", "ideas.DanceDescription": "Design an animated dance scene with music and dance moves.", "ideas.CatchTitle": "Catch Game", diff --git a/src/views/ideas/ttt.json b/src/views/ideas/ttt.json index 1c3ea3bab..0b463ba83 100644 --- a/src/views/ideas/ttt.json +++ b/src/views/ideas/ttt.json @@ -3,7 +3,9 @@ "title": "ideas.animateANameTitle", "description": "ideas.animateANameDescription", "thumbImage": "/images/ideas/activities/animate-a-name-thumb.jpg", + "thumbImageDescription": "ideas.animateANameImageDescription", "modalImage": "/images/ideas/activities/animate-a-name-modal.jpg", + "modalImageDescription": "ideas.animateANameImageDescription", "tutorialUrl": "name", "cardsUrl": "cards.name-cardsLink", "guideUrl": "guides.NameGuideLink" @@ -12,7 +14,9 @@ "title": "ideas.ImagineTitle", "description": "ideas.ImagineDescription", "thumbImage": "/images/ideas/activities/imagine-thumb.jpg", + "thumbImageDescription": "ideas.ImagineImageDescription", "modalImage": "/images/ideas/activities/imagine-modal.jpg", + "modalImageDescription": "ideas.ImagineImageDescription", "tutorialUrl": "imagine", "cardsUrl": "cards.imagine-cardsLink", "guideUrl": "guides.ImagineGuideLink" @@ -21,7 +25,9 @@ "title": "ideas.chaseGameTitle", "description": "ideas.chaseGameDescription", "thumbImage": "/images/ideas/activities/chase-game-thumb.jpg", + "thumbImageDescription": "ideas.chaseGameImageDescription", "modalImage": "/images/ideas/activities/chase-game-modal.jpg", + "modalImageDescription": "ideas.chaseGameImageDescription", "tutorialUrl": "chase-game", "cardsUrl": "cards.chase-cardsLink", "guideUrl": "guides.ChaseGuideLink" @@ -30,7 +36,9 @@ "title": "ideas.makeMusicTitle", "description": "ideas.makeMusicDescription", "thumbImage": "/images/ideas/activities/make-music-thumb.jpg", + "thumbImageDescription": "ideas.makeMusicImageDescription", "modalImage": "/images/ideas/activities/make-music-modal.jpg", + "modalImageDescription": "ideas.makeMusicImageDescription", "tutorialUrl": "music", "cardsUrl": "cards.music-cardsLink", "guideUrl": "guides.MusicGuideLink" @@ -39,7 +47,9 @@ "title": "ideas.createAStoryTitle", "description": "ideas.createAStoryDescription", "thumbImage": "/images/ideas/activities/create-a-story-thumb.jpg", + "thumbImageDescription": "ideas.createAStoryImageDescription", "modalImage": "/images/ideas/activities/create-a-story-modal.jpg", + "modalImageDescription": "ideas.createAStoryImageDescription", "tutorialUrl": "tell-a-story", "cardsUrl": "cards.story-cardsLink", "guideUrl": "guides.StoryGuideLink" @@ -48,7 +58,9 @@ "title": "ideas.MakeItFlyTitle", "description": "ideas.MakeItFlyDescription", "thumbImage": "/images/ideas/activities/fly-thumb.jpg", + "thumbImageDescription": "ideas.MakeItFlyImageDescription", "modalImage": "/images/ideas/activities/fly-modal.jpg", + "modalImageDescription": "ideas.MakeItFlyImageDescription", "tutorialUrl": "make-it-fly", "cardsUrl": "cards.fly-cardsLink", "guideUrl": "guides.FlyGuideLink" @@ -57,7 +69,9 @@ "title": "ideas.PongTitle", "description": "ideas.PongDescription", "thumbImage": "/images/ideas/activities/pong-thumb.jpg", + "thumbImageDescription": "ideas.PongImageDescription", "modalImage": "/images/ideas/activities/pong-modal.jpg", + "modalImageDescription": "ideas.PongImageDescription", "tutorialUrl": "pong", "cardsUrl": "cards.pong-cardsLink", "guideUrl": "guides.PongGuideLink" @@ -66,7 +80,9 @@ "title": "ideas.animateACharacterTitle", "description": "ideas.animateACharacterDescription", "thumbImage": "/images/ideas/activities/animate-a-character-thumb.jpg", + "thumbImageDescription": "ideas.animateACharacterImageDescription", "modalImage": "/images/ideas/activities/animate-a-character-modal.jpg", + "modalImageDescription": "ideas.animateACharacterImageDescription", "tutorialUrl": "animate-a-character", "cardsUrl": "cards.animation-cardsLink", "guideUrl": "guides.AnimateGuideLink" @@ -75,7 +91,9 @@ "title": "ideas.videoSensingTitle", "description": "ideas.videoSensingDescription", "thumbImage": "/images/ideas/activities/video-sensing-thumb.jpg", + "thumbImageDescription": "ideas.videoSensingImageDescription", "modalImage": "/images/ideas/activities/video-sensing-modal.jpg", + "modalImageDescription": "ideas.videoSensingImageDescription", "tutorialUrl": "video-sensing", "cardsUrl": "cards.video-cardsLink", "guideUrl": "guides.VideoGuideLink" diff --git a/src/views/search/search.jsx b/src/views/search/search.jsx index c5d1d4c27..74d18f99f 100644 --- a/src/views/search/search.jsx +++ b/src/views/search/search.jsx @@ -31,8 +31,7 @@ class Search extends React.Component { bindAll(this, [ 'getSearchState', 'handleChangeSortMode', - 'handleGetSearchMore', - 'getTab' + 'handleGetSearchMore' ]); this.state = this.getSearchState(); this.state.loaded = []; @@ -151,38 +150,6 @@ class Search extends React.Component { }); }); } - getTab (type) { - const termText = this.encodeSearchTerm(); - let targetUrl = `/search/${type}`; - if (termText) { - targetUrl += `?q=${termText}`; - } - let allTab = ( - -
  • - - -
  • -
    - ); - if (this.state.tab === type) { - allTab = ( - -
  • - - -
  • -
    - ); - } - return allTab; - } getProjectBox () { const results = (

    - - {this.getTab('projects')} - {this.getTab('studios')} - + { + const termText = this.encodeSearchTerm(); + let targetUrl = `/search/projects`; + if (termText) targetUrl += `?q=${termText}`; + window.location = targetUrl; + }, + getContent: isActive => ( +
    + {isActive ? ( + + ) : ( + + ) + } + +
    + ) + }, + { + name: 'studios', + onTrigger: () => { + const termText = this.encodeSearchTerm(); + let targetUrl = `/search/studios`; + if (termText) targetUrl += `?q=${termText}`; + window.location = targetUrl; + }, + getContent: isActive => ( +
    + {isActive ? ( + + ) : ( + + ) + } + +
    + ) + } + ]} + activeTabName={this.state.tab} + />