diff --git a/src/components/asset-button/asset-button.css b/src/components/asset-button/asset-button.css new file mode 100644 index 000000000..b36fa76b8 --- /dev/null +++ b/src/components/asset-button/asset-button.css @@ -0,0 +1,21 @@ +@import "../../css/colors.css"; + +.container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + background: $motion-primary; + border-radius: 100%; + width: 2.75rem; + height: 2.75rem; + outline: none; + border: none; +} + +.icon { + width: 1.75rem; + height: 1.75rem; +} diff --git a/src/components/asset-button/asset-button.jsx b/src/components/asset-button/asset-button.jsx new file mode 100644 index 000000000..7cd6cb6e6 --- /dev/null +++ b/src/components/asset-button/asset-button.jsx @@ -0,0 +1,31 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import classNames from 'classnames'; +import styles from './asset-button.css'; + +const AssetButton = ({ + img, + className, + title, + onClick +}) => ( + +); + +AssetButton.propTypes = { + className: PropTypes.string, + img: PropTypes.string, + onClick: PropTypes.func.isRequired, + title: PropTypes.node.isRequired +}; + +export default AssetButton; diff --git a/src/components/asset-panel/icon--add-backdrop-lib.svg b/src/components/asset-panel/icon--add-backdrop-lib.svg index 8c80f17aa..2294afd72 100644 --- a/src/components/asset-panel/icon--add-backdrop-lib.svg +++ b/src/components/asset-panel/icon--add-backdrop-lib.svg @@ -1,31 +1,21 @@ - - - - add-bg + + + + backdrop-library Created with Sketch. - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + - \ No newline at end of file + diff --git a/src/components/asset-panel/icon--add-blank-costume.svg b/src/components/asset-panel/icon--add-blank-costume.svg index 20843fe61..1a5014698 100644 --- a/src/components/asset-panel/icon--add-blank-costume.svg +++ b/src/components/asset-panel/icon--add-blank-costume.svg @@ -1,18 +1,12 @@ - - - - add sprite + + + + paint Created with Sketch. - - - - - - - - - + + + - \ No newline at end of file + diff --git a/src/components/asset-panel/icon--add-costume-lib.svg b/src/components/asset-panel/icon--add-costume-lib.svg index cb364d3b0..5e30024a2 100644 --- a/src/components/asset-panel/icon--add-costume-lib.svg +++ b/src/components/asset-panel/icon--add-costume-lib.svg @@ -1,30 +1,12 @@ - - - - add-sprite + + + + sprite-library Created with Sketch. - - - - - - - - - - - - - - - - - - - - - + + + - \ No newline at end of file + diff --git a/src/components/asset-panel/icon--add-sound-lib.svg b/src/components/asset-panel/icon--add-sound-lib.svg index 1293940a9..b279dc52c 100644 --- a/src/components/asset-panel/icon--add-sound-lib.svg +++ b/src/components/asset-panel/icon--add-sound-lib.svg @@ -1,26 +1,12 @@ - - - - sound icon + + + + sound-library Created with Sketch. - - - - - - - - - - - - - - - - + + - \ No newline at end of file + diff --git a/src/components/asset-panel/icon--add-sound-record.svg b/src/components/asset-panel/icon--add-sound-record.svg index b82e7a412..9feb24cfd 100644 --- a/src/components/asset-panel/icon--add-sound-record.svg +++ b/src/components/asset-panel/icon--add-sound-record.svg @@ -1,25 +1,12 @@ - - - - record icon + + + + record Created with Sketch. - - - - - - - - - - - - - - - + + - \ No newline at end of file + diff --git a/src/components/asset-panel/selector.css b/src/components/asset-panel/selector.css index 546a7863d..2a19296d6 100644 --- a/src/components/asset-panel/selector.css +++ b/src/components/asset-panel/selector.css @@ -15,30 +15,13 @@ flex-direction: column; align-items: center; justify-content: space-around; - margin: 1.25rem 0; + margin: 0.75rem 0; color: $motion-primary; text-align: center; } -.new-button { - display: flex; - flex-direction: column; - align-items: center; - font-size: 0.75rem; - cursor: pointer; - transition: 0.2s; -} - -.new-button:hover { - transform: scale(1.2); -} - -.new-button + .new-button { - margin-top: 1.25rem; -} - -.new-button-icon + .new-button-label { - margin-top: 0.5rem; +.new-buttons > button + button { + margin-top: 0.75rem; } .list-area { diff --git a/src/components/asset-panel/selector.jsx b/src/components/asset-panel/selector.jsx index c6eec7f78..012206517 100644 --- a/src/components/asset-panel/selector.jsx +++ b/src/components/asset-panel/selector.jsx @@ -4,7 +4,7 @@ import React from 'react'; import SpriteSelectorItem from '../../containers/sprite-selector-item.jsx'; import Box from '../box/box.jsx'; -import IconButton from '../icon-button/icon-button.jsx'; +import AssetButton from '../asset-button/asset-button.jsx'; import styles from './selector.css'; const Selector = props => { @@ -35,7 +35,7 @@ const Selector = props => { {buttons.map(({message, img, onClick}, index) => ( - { Selector.propTypes = { buttons: PropTypes.arrayOf(PropTypes.shape({ - message: PropTypes.node.isRequired, + message: PropTypes.string.isRequired, img: PropTypes.string.isRequired, onClick: PropTypes.func.isRequired })), diff --git a/src/components/gui/gui.css b/src/components/gui/gui.css index 2c0533e98..92b83acc2 100644 --- a/src/components/gui/gui.css +++ b/src/components/gui/gui.css @@ -150,16 +150,26 @@ bottom: 0; left: 0; z-index: 50; /** Force extension button above the ScratchBlocks flyout. */ - background: white; + background: $motion-primary; - border: 1px solid #ddd; + border: 1px solid $motion-primary; box-sizing: content-box; /* To match scratch-block vertical toolbox borders */ } .extension-button { - font-size: 0.55rem; - font-weight: bold; + background: none; + border: none; + outline: none; + width: 100%; + height: 100%; + cursor: pointer; } + +.extension-button-icon { + width: 1.75rem; + height: 1.75rem; +} + .extension-button > div { margin-top: 0; } diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index d50ea4577..33b13e454 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -1,9 +1,9 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; +import {defineMessages, injectIntl, intlShape} from 'react-intl'; import {Tab, Tabs, TabList, TabPanel} from 'react-tabs'; import MediaQuery from 'react-responsive'; -import {FormattedMessage} from 'react-intl'; import tabStyles from 'react-tabs/style/react-tabs.css'; import VM from 'scratch-vm'; import Renderer from 'scratch-render'; @@ -17,7 +17,6 @@ import Stage from '../../containers/stage.jsx'; import Box from '../box/box.jsx'; import FeedbackForm from '../feedback-form/feedback-form.jsx'; -import IconButton from '../icon-button/icon-button.jsx'; import MenuBar from '../menu-bar/menu-bar.jsx'; import PreviewModal from '../../containers/preview-modal.jsx'; import WebGlModal from '../../containers/webgl-modal.jsx'; @@ -26,19 +25,20 @@ import layout from '../../lib/layout-constants.js'; import styles from './gui.css'; import addExtensionIcon from './icon--extensions.svg'; -const addExtensionMessage = ( - -); +const messages = defineMessages({ + addExtension: { + id: 'gui.gui.addExtension', + description: 'Button to add an extension in the target pane', + defaultMessage: 'Add Extension' + } +}); const GUIComponent = props => { const { basePath, children, enableExtensions, + intl, feedbackFormVisible, vm, previewInfoVisible, @@ -108,14 +108,18 @@ const GUIComponent = props => { /> - + > + + @@ -161,6 +165,7 @@ GUIComponent.propTypes = { children: PropTypes.node, enableExtensions: PropTypes.bool, feedbackFormVisible: PropTypes.bool, + intl: intlShape.isRequired, onExtensionButtonClick: PropTypes.func, onTabSelect: PropTypes.func, previewInfoVisible: PropTypes.bool, @@ -170,4 +175,4 @@ GUIComponent.propTypes = { GUIComponent.defaultProps = { basePath: './' }; -export default GUIComponent; +export default injectIntl(GUIComponent); diff --git a/src/components/gui/icon--extensions.svg b/src/components/gui/icon--extensions.svg index de96e820c..5d50761c0 100644 --- a/src/components/gui/icon--extensions.svg +++ b/src/components/gui/icon--extensions.svg @@ -7,8 +7,8 @@ - - + + diff --git a/src/components/sprite-selector/icon--sprite.svg b/src/components/sprite-selector/icon--sprite.svg index cb364d3b0..12c4a8b36 100644 --- a/src/components/sprite-selector/icon--sprite.svg +++ b/src/components/sprite-selector/icon--sprite.svg @@ -1,30 +1,12 @@ - - - - add-sprite + + + + sprite-library Created with Sketch. - - - - - - - - - - - - - - - - - - - - - + + + \ No newline at end of file diff --git a/src/components/sprite-selector/sprite-selector.css b/src/components/sprite-selector/sprite-selector.css index 8c1e2315a..67b0532d3 100644 --- a/src/components/sprite-selector/sprite-selector.css +++ b/src/components/sprite-selector/sprite-selector.css @@ -61,8 +61,6 @@ } .add-button { - font-size: 0.55rem; - font-weight: bold; position: absolute; bottom: 0.75rem; right: 1rem; diff --git a/src/components/sprite-selector/sprite-selector.jsx b/src/components/sprite-selector/sprite-selector.jsx index 7196176ae..41e51a316 100644 --- a/src/components/sprite-selector/sprite-selector.jsx +++ b/src/components/sprite-selector/sprite-selector.jsx @@ -1,25 +1,26 @@ import PropTypes from 'prop-types'; import React from 'react'; -import {FormattedMessage} from 'react-intl'; +import {defineMessages, injectIntl, intlShape} from 'react-intl'; import Box from '../box/box.jsx'; import SpriteInfo from '../../containers/sprite-info.jsx'; import SpriteSelectorItem from '../../containers/sprite-selector-item.jsx'; -import IconButton from '../icon-button/icon-button.jsx'; +import AssetButton from '../asset-button/asset-button.jsx'; import styles from './sprite-selector.css'; import spriteIcon from './icon--sprite.svg'; -const addSpriteMessage = ( - -); +const messages = defineMessages({ + addSprite: { + id: 'gui.spriteSelector.addSprite', + description: 'Button to add a sprite in the target pane', + defaultMessage: 'Add Sprite' + } +}); const SpriteSelectorComponent = function (props) { const { + intl, onChangeSpriteDirection, onChangeSpriteName, onChangeSpriteSize, @@ -84,10 +85,10 @@ const SpriteSelectorComponent = function (props) { } - @@ -95,6 +96,7 @@ const SpriteSelectorComponent = function (props) { }; SpriteSelectorComponent.propTypes = { + intl: intlShape.isRequired, onChangeSpriteDirection: PropTypes.func, onChangeSpriteName: PropTypes.func, onChangeSpriteSize: PropTypes.func, @@ -121,4 +123,4 @@ SpriteSelectorComponent.propTypes = { }) }; -export default SpriteSelectorComponent; +export default injectIntl(SpriteSelectorComponent); diff --git a/src/components/stage-selector/icon--backdrop.svg b/src/components/stage-selector/icon--backdrop.svg index 8c80f17aa..12fa6c7ab 100644 --- a/src/components/stage-selector/icon--backdrop.svg +++ b/src/components/stage-selector/icon--backdrop.svg @@ -1,30 +1,20 @@ - - - - add-bg + + + + backdrop-library Created with Sketch. - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/src/components/stage-selector/stage-selector.css b/src/components/stage-selector/stage-selector.css index 06dff7210..a6fe0b042 100644 --- a/src/components/stage-selector/stage-selector.css +++ b/src/components/stage-selector/stage-selector.css @@ -76,10 +76,6 @@ $header-height: calc($stage-menu-height - 2px); } .add-button { - font-size: 0.55rem; - font-weight: bold; - text-align: center; position: absolute; bottom: 0.75rem; - left: 0.25rem; } diff --git a/src/components/stage-selector/stage-selector.jsx b/src/components/stage-selector/stage-selector.jsx index 5ffad63e5..eea811409 100644 --- a/src/components/stage-selector/stage-selector.jsx +++ b/src/components/stage-selector/stage-selector.jsx @@ -1,25 +1,26 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; -import {FormattedMessage} from 'react-intl'; +import {defineMessages, intlShape, injectIntl, FormattedMessage} from 'react-intl'; import Box from '../box/box.jsx'; -import IconButton from '../icon-button/icon-button.jsx'; +import AssetButton from '../asset-button/asset-button.jsx'; import CostumeCanvas from '../costume-canvas/costume-canvas.jsx'; import styles from './stage-selector.css'; import backdropIcon from './icon--backdrop.svg'; -const addBackdropMessage = ( - -); +const messages = defineMessages({ + addBackdrop: { + id: 'gui.stageSelector.targetPaneAddBackdrop', + description: 'Button to add a backdrop in the target pane', + defaultMessage: 'Add Backdrop' + } +}); const StageSelector = props => { const { backdropCount, + intl, selected, url, onClick, @@ -53,10 +54,10 @@ const StageSelector = props => { />
{backdropCount}
- @@ -65,9 +66,10 @@ const StageSelector = props => { StageSelector.propTypes = { backdropCount: PropTypes.number.isRequired, + intl: intlShape.isRequired, onClick: PropTypes.func, onNewBackdropClick: PropTypes.func, selected: PropTypes.bool.isRequired, url: PropTypes.string }; -export default StageSelector; +export default injectIntl(StageSelector); diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx index a142ff912..be4c554fe 100644 --- a/src/containers/costume-tab.jsx +++ b/src/containers/costume-tab.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import bindAll from 'lodash.bindall'; -import {FormattedMessage} from 'react-intl'; +import {defineMessages, intlShape, injectIntl} from 'react-intl'; import VM from 'scratch-vm'; import AssetPanel from '../components/asset-panel/asset-panel.jsx'; @@ -22,36 +22,28 @@ import addLibraryBackdropIcon from '../components/asset-panel/icon--add-backdrop import addLibraryCostumeIcon from '../components/asset-panel/icon--add-costume-lib.svg'; import costumeLibraryContent from '../lib/libraries/costumes.json'; -const messages = { - addLibraryBackdropMsg: ( - - ), - addLibraryCostumeMsg: ( - - ), - addBlankBackdropMsg: ( - - ), - addBlankCostumeMsg: ( - - ) -}; +const messages = defineMessages({ + addLibraryBackdropMsg: { + defaultMessage: 'Add Backdrop From Library', + description: 'Button to add a backdrop in the editor tab', + id: 'gui.costumeTab.addBackdrop' + }, + addLibraryCostumeMsg: { + defaultMessage: 'Add Costume From Library', + description: 'Button to add a costume in the editor tab', + id: 'gui.costumeTab.addCostume' + }, + addBlankBackdropMsg: { + defaultMessage: 'Add Blank Backdrop', + description: 'Button to add a blank backdrop in the editor tab', + id: 'gui.costumeTab.addBlankBackdrop' + }, + addBlankCostumeMsg: { + defaultMessage: 'Add Blank Costume', + description: 'Button to add a blank costume in the editor tab', + id: 'gui.costumeTab.addBlankCostume' + } +}); class CostumeTab extends React.Component { constructor (props) { @@ -108,6 +100,7 @@ class CostumeTab extends React.Component { render () { // For paint wrapper const { + intl, onNewLibraryBackdropClick, onNewLibraryCostumeClick, costumeLibraryVisible, @@ -139,12 +132,12 @@ class CostumeTab extends React.Component { ({ } }); -export default connect( +export default injectIntl(connect( mapStateToProps, mapDispatchToProps -)(CostumeTab); +)(CostumeTab)); diff --git a/src/containers/sound-tab.jsx b/src/containers/sound-tab.jsx index 01ddbe539..9e30ba2ed 100644 --- a/src/containers/sound-tab.jsx +++ b/src/containers/sound-tab.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import bindAll from 'lodash.bindall'; -import {FormattedMessage} from 'react-intl'; +import {defineMessages, intlShape, injectIntl} from 'react-intl'; import VM from 'scratch-vm'; import AssetPanel from '../components/asset-panel/asset-panel.jsx'; @@ -64,6 +64,7 @@ class SoundTab extends React.Component { render () { const { + intl, vm, onNewSoundFromLibraryClick, onNewSoundFromRecordingClick @@ -82,29 +83,27 @@ class SoundTab extends React.Component { } )) : []; - const recordSoundMsg = ( - - ); - const addSoundMsg = ( - - ); + const messages = defineMessages({ + recordSound: { + defaultMessage: 'Record Sound', + description: 'Button to record a sound in the editor tab', + id: 'gui.soundTab.recordSound' + }, + addSound: { + defaultMessage: 'Add Sound', + description: 'Button to add a sound in the editor tab', + id: 'gui.soundTab.addSound' + } + }); return ( ({ } }); -export default connect( +export default injectIntl(connect( mapStateToProps, mapDispatchToProps -)(SoundTab); +)(SoundTab)); diff --git a/test/integration/costumes.test.js b/test/integration/costumes.test.js index b19576bf2..98f31629a 100644 --- a/test/integration/costumes.test.js +++ b/test/integration/costumes.test.js @@ -27,7 +27,7 @@ describe('Working with costumes', () => { await loadUri(uri); await clickXpath('//button[@title="tryit"]'); await clickText('Costumes'); - await clickText('Add Costume'); + await clickXpath('//button[@title="Add Costume"]'); const el = await findByXpath("//input[@placeholder='what are you looking for?']"); await el.sendKeys('abb'); await clickText('Abby-a'); // Should close the modal, then click the costumes in the selector @@ -39,7 +39,7 @@ describe('Working with costumes', () => { test('Adding a backdrop', async () => { await loadUri(uri); await clickXpath('//button[@title="tryit"]'); - await clickText('Add Backdrop'); + await clickXpath('//button[@title="Add Backdrop"]'); const el = await findByXpath("//input[@placeholder='what are you looking for?']"); await el.sendKeys('blue'); await clickText('Blue Sky'); // Should close the modal diff --git a/test/integration/localization.test.js b/test/integration/localization.test.js index b99066a35..7c90b3221 100644 --- a/test/integration/localization.test.js +++ b/test/integration/localization.test.js @@ -30,7 +30,7 @@ describe('Localization', () => { await loadUri(uri); await clickXpath('//button[@title="tryit"]'); await clickText('Blocks'); - await clickText('Extensions'); + await clickXpath('//button[@title="Add Extension"]'); await clickText('Pen', scope.modal); // Modal closes await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation await clickText('English'); diff --git a/test/integration/sounds.test.js b/test/integration/sounds.test.js index 475d22719..244ebb9b4 100644 --- a/test/integration/sounds.test.js +++ b/test/integration/sounds.test.js @@ -37,13 +37,13 @@ describe('Working with sounds', () => { .accept(); // Add it back - await clickText('Add Sound'); + await clickXpath('//button[@title="Add Sound"]'); let el = await findByXpath("//input[@placeholder='what are you looking for?']"); await el.sendKeys('meow'); await clickText('Meow', scope.modal); // Should close the modal // Add a new sound - await clickText('Add Sound'); + await clickXpath('//button[@title="Add Sound"]'); el = await findByXpath("//input[@placeholder='what are you looking for?']"); await el.sendKeys('chom'); await clickText('Chomp'); // Should close the modal, then click the sounds in the selector @@ -70,11 +70,11 @@ describe('Working with sounds', () => { // Add a sound so this sprite has 2 sounds. await clickText('Sounds'); - await clickText('Add Sound'); + await clickXpath('//button[@title="Add Sound"]'); await clickText('A Bass'); // Closes the modal // Now add a sprite with only one sound. - await clickText('Add Sprite'); + await clickXpath('//button[@title="Add Sprite"]'); await clickText('Abby'); // Doing this used to crash the editor. await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for error