diff --git a/.npmignore b/.npmignore index 61247064a407888b80af36682d29f7f93d687143..dee8a6a5d92f38f72bce5e6383a990b01a5fd28d 100644 --- a/.npmignore +++ b/.npmignore @@ -5,6 +5,9 @@ /node_modules npm-* +# Double copies of all the static assets and tutorial gifs +/src + # Testing /.nyc_output /coverage diff --git a/.travis.yml b/.travis.yml index 38af9f8b26444e4ca3701e262f9fdd1038bfd879..2a9152628ca2b0ac80edcd6226517556a2282111 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,6 +57,7 @@ deploy: - master - develop - smoke + - hotfix/* condition: $TRAVIS_EVENT_TYPE != cron skip_cleanup: true script: if npm info scratch-gui | grep -q $RELEASE_VERSION; then git tag $RELEASE_VERSION && git push https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git $RELEASE_VERSION; fi diff --git a/package-lock.json b/package-lock.json index 9d1229decad3e5335764816f6149dc96497d95cd..dd51feeb208bf336b7cf863b107f9aa9711b7aa6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2699,9 +2699,9 @@ } }, "chromedriver": { - "version": "77.0.0", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-77.0.0.tgz", - "integrity": "sha512-mZa1IVx4HD8rDaItWbnS470mmypgiWsDiu98r0NkiT4uLm3qrANl4vOU6no6vtWtLQiW5kt1POcIbjeNpsLbXA==", + "version": "78.0.1", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-78.0.1.tgz", + "integrity": "sha512-eOsyFk4xb9EECs1VMrDbxO713qN+Bu1XUE8K9AuePc3839TPdAegg72kpXSzkeNqRNZiHbnJUItIVCLFkDqceA==", "dev": true, "requires": { "del": "^4.1.1", @@ -11460,9 +11460,9 @@ } }, "scratch-blocks": { - "version": "0.1.0-prerelease.1570730963", - "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.1570730963.tgz", - "integrity": "sha512-4rTLas2jImF/H3WE93CXwBYGuzVXgiLfF654EL96HXxViuBDNg35UE5VAyextKMxj4AGGULoVdnZaGIV9AfrjQ==", + "version": "0.1.0-prerelease.1572384380", + "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.1572384380.tgz", + "integrity": "sha512-DTmX9wcShFV/cFNQt1rmexttJIe4hr11nz/omVKLovRsVUKaKJqSxpwbfjduqI9lj/xzCgYzfpC0EtjZFZmbRQ==", "dev": true, "requires": { "exports-loader": "0.6.3", @@ -11470,9 +11470,9 @@ } }, "scratch-l10n": { - "version": "3.6.20191008224547", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.6.20191008224547.tgz", - "integrity": "sha512-J6AgB6oB+/ibamUNeyTdtSvkPzJchiD50xoUqzzlcPOv+AWOFSTOakGPzJnGE6/WeZ0njBThvy1rh23lamqiow==", + "version": "3.6.20191029224007", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.6.20191029224007.tgz", + "integrity": "sha512-12LprZ35Z7j/h14CtmU0ZW+aHwOUme58bwIpF/dINil9bbUhasLzGd1Ov60y3eOmP0LO+EE4oebUbK6KV1rguQ==", "dev": true, "requires": { "@babel/cli": "^7.1.2", @@ -11482,9 +11482,9 @@ } }, "scratch-paint": { - "version": "0.2.0-prerelease.20191010161144", - "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-0.2.0-prerelease.20191010161144.tgz", - "integrity": "sha512-mItiFbEOWMblwJnFjbM1VBp5bGGkGCM4uc4fM2ej40hjQotD2SAhHfGPHhLRhtk3vEq+mcyq4iJfJo2h3Hqmkg==", + "version": "0.2.0-prerelease.20191104214909", + "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-0.2.0-prerelease.20191104214909.tgz", + "integrity": "sha512-MYGnFgK0EVQn26yy01fZhjDvVHc/jjjzg19/7PF1sTHnligflTMeticRv3AesqjjVZzUbWmUdswQAnfDHb54Wg==", "dev": true, "requires": { "@scratch/paper": "0.11.20190729152410", @@ -11495,7 +11495,7 @@ "minilog": "3.1.0", "parse-color": "1.0.0", "prop-types": "^15.5.10", - "scratch-svg-renderer": "0.2.0-prerelease.20190822202608" + "scratch-svg-renderer": "0.2.0-prerelease.20191104164753" }, "dependencies": { "classnames": { @@ -11597,9 +11597,9 @@ } }, "scratch-render": { - "version": "0.1.0-prerelease.20191001200908", - "resolved": "https://registry.npmjs.org/scratch-render/-/scratch-render-0.1.0-prerelease.20191001200908.tgz", - "integrity": "sha512-9vgCM/C44Pg6zd3jnRZXGaxytlrXSlI7lYgXfllCiSgMxfuBs3pgQKmEFQFj4gwBYs3mykp+j6WFpqU09hAwwA==", + "version": "0.1.0-prerelease.20191104214419", + "resolved": "https://registry.npmjs.org/scratch-render/-/scratch-render-0.1.0-prerelease.20191104214419.tgz", + "integrity": "sha512-EmXRP5nyY/gayC/Gb02ZQ6fvqOQs9C8fDoaO05WLEIjLa2QRQHVaueOM6FO00p04KeNh98LMaNcqYOeqv7f9kg==", "dev": true, "requires": { "grapheme-breaker": "0.3.2", @@ -11609,7 +11609,7 @@ "minilog": "3.1.0", "raw-loader": "^0.5.1", "scratch-storage": "^1.0.0", - "scratch-svg-renderer": "0.2.0-prerelease.20190822202608", + "scratch-svg-renderer": "0.2.0-prerelease.20191104164753", "twgl.js": "4.4.0" } }, @@ -11657,9 +11657,9 @@ } }, "scratch-svg-renderer": { - "version": "0.2.0-prerelease.20190822202608", - "resolved": "https://registry.npmjs.org/scratch-svg-renderer/-/scratch-svg-renderer-0.2.0-prerelease.20190822202608.tgz", - "integrity": "sha512-7y1+XJW+1GrqWxV8c91Cla8sbKL18YKnqNplg3enfQKy7UhZ4G+HJVhFH/SbTqdWW5qpj02eAfgGwBHwvy7tng==", + "version": "0.2.0-prerelease.20191104164753", + "resolved": "https://registry.npmjs.org/scratch-svg-renderer/-/scratch-svg-renderer-0.2.0-prerelease.20191104164753.tgz", + "integrity": "sha512-K++VXmapGZ9pxlBT8KNHQqOQQ5xfXR3K7Wocj8G+Ap8CJ/qxfirvorGCpVW7KrdHj912a1Logw1Pwx+16/fl7A==", "dev": true, "requires": { "base64-js": "1.2.1", diff --git a/package.json b/package.json index de3cfdeff634a40ac25df6cc5de20b94fc45e870..121d3432add1b5f2b41b077128cbaa7af0184b5f 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "babel-loader": "^8.0.4", "base64-loader": "1.0.0", "bowser": "1.9.4", - "chromedriver": "77.0.0", + "chromedriver": "78.0.1", "classnames": "2.2.6", "computed-style-to-inline-style": "3.0.0", "copy-webpack-plugin": "^4.5.1", @@ -108,12 +108,12 @@ "redux-throttle": "0.1.1", "rimraf": "^2.6.1", "scratch-audio": "0.1.0-prerelease.20190925183642", - "scratch-l10n": "3.6.20191008224547", - "scratch-blocks": "0.1.0-prerelease.1570730963", - "scratch-paint": "0.2.0-prerelease.20191010161144", - "scratch-render": "0.1.0-prerelease.20191001200908", + "scratch-l10n": "3.6.20191029224007", + "scratch-blocks": "0.1.0-prerelease.1572384380", + "scratch-paint": "0.2.0-prerelease.20191104214909", + "scratch-render": "0.1.0-prerelease.20191104214419", "scratch-storage": "1.3.2", - "scratch-svg-renderer": "0.2.0-prerelease.20190822202608", + "scratch-svg-renderer": "0.2.0-prerelease.20191104164753", "scratch-vm": "0.2.0-prerelease.20191018142546", "selenium-webdriver": "3.6.0", "startaudiocontext": "1.2.1", diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index 3c68eec90bf6d96b467f5bc18cf5790b0cce350e..9846eed7566356ed1e5395def9b59388bb870958 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -94,7 +94,6 @@ const GUIComponent = props => { onLogOut, onOpenRegistration, onToggleLoginOpen, - onUpdateProjectTitle, onActivateCostumesTab, onActivateSoundsTab, onActivateTab, @@ -228,7 +227,6 @@ const GUIComponent = props => { onSeeCommunity={onSeeCommunity} onShare={onShare} onToggleLoginOpen={onToggleLoginOpen} - onUpdateProjectTitle={onUpdateProjectTitle} /> <Box className={styles.bodyWrapper}> <Box className={styles.flexWrapper}> @@ -406,7 +404,6 @@ GUIComponent.propTypes = { onTelemetryModalOptIn: PropTypes.func, onTelemetryModalOptOut: PropTypes.func, onToggleLoginOpen: PropTypes.func, - onUpdateProjectTitle: PropTypes.func, renderLogin: PropTypes.func, showComingSoon: PropTypes.bool, soundsTabVisible: PropTypes.bool, @@ -433,7 +430,6 @@ GUIComponent.defaultProps = { isCreating: false, isShared: false, loading: false, - onUpdateProjectTitle: () => {}, showComingSoon: false, stageSizeMode: STAGE_SIZE_MODES.large }; diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx index 1fa7a01cc1974236104490d11086e64183850073..98bc128a92f11fe272d674513930e53f897d58bb 100644 --- a/src/components/menu-bar/menu-bar.jsx +++ b/src/components/menu-bar/menu-bar.jsx @@ -395,7 +395,6 @@ class MenuBar extends React.Component { <SBFileUploader canSave={this.props.canSave} userOwnsProject={this.props.userOwnsProject} - onUpdateProjectTitle={this.props.onUpdateProjectTitle} > {(className, renderFileInput, handleLoadProject) => ( <MenuItem @@ -495,7 +494,6 @@ class MenuBar extends React.Component { > <ProjectTitleInput className={classNames(styles.titleFieldGrowable)} - onUpdateProjectTitle={this.props.onUpdateProjectTitle} /> </MenuBarItemTooltip> </div> @@ -746,7 +744,6 @@ MenuBar.propTypes = { onSeeCommunity: PropTypes.func, onShare: PropTypes.func, onToggleLoginOpen: PropTypes.func, - onUpdateProjectTitle: PropTypes.func, projectTitle: PropTypes.string, renderLogin: PropTypes.func, sessionExists: PropTypes.bool, diff --git a/src/components/menu-bar/project-title-input.jsx b/src/components/menu-bar/project-title-input.jsx index b9b5aa6d8382e55c8483a4dde3290ae1ed6ad44a..fe7647cb0c9ae89002799ea5cbd11233431c7c40 100644 --- a/src/components/menu-bar/project-title-input.jsx +++ b/src/components/menu-bar/project-title-input.jsx @@ -1,9 +1,9 @@ import classNames from 'classnames'; import {connect} from 'react-redux'; import PropTypes from 'prop-types'; -import bindAll from 'lodash.bindall'; import React from 'react'; import {defineMessages, intlShape, injectIntl} from 'react-intl'; +import {setProjectTitle} from '../../reducers/project-title'; import BufferedInputHOC from '../forms/buffered-input-hoc.jsx'; import Input from '../forms/input.jsx'; @@ -19,39 +19,27 @@ const messages = defineMessages({ } }); -class ProjectTitleInput extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleUpdateProjectTitle' - ]); - } - // call onUpdateProjectTitle if it is defined (only defined when gui - // is used within scratch-www) - handleUpdateProjectTitle (newTitle) { - if (this.props.onUpdateProjectTitle) { - this.props.onUpdateProjectTitle(newTitle); - } - } - render () { - return ( - <BufferedInput - className={classNames(styles.titleField, this.props.className)} - maxLength="100" - placeholder={this.props.intl.formatMessage(messages.projectTitlePlaceholder)} - tabIndex="0" - type="text" - value={this.props.projectTitle} - onSubmit={this.handleUpdateProjectTitle} - /> - ); - } -} +const ProjectTitleInput = ({ + className, + intl, + onSubmit, + projectTitle +}) => ( + <BufferedInput + className={classNames(styles.titleField, className)} + maxLength="100" + placeholder={intl.formatMessage(messages.projectTitlePlaceholder)} + tabIndex="0" + type="text" + value={projectTitle} + onSubmit={onSubmit} + /> +); ProjectTitleInput.propTypes = { className: PropTypes.string, intl: intlShape.isRequired, - onUpdateProjectTitle: PropTypes.func, + onSubmit: PropTypes.func, projectTitle: PropTypes.string }; @@ -59,7 +47,9 @@ const mapStateToProps = state => ({ projectTitle: state.scratchGui.projectTitle }); -const mapDispatchToProps = () => ({}); +const mapDispatchToProps = dispatch => ({ + onSubmit: title => dispatch(setProjectTitle(title)) +}); export default injectIntl(connect( mapStateToProps, diff --git a/src/components/monitor/monitor.css b/src/components/monitor/monitor.css index 97a62e02d23916200db10035b79b42f2adc4aa3d..521c39279aacda5896cf48c9ad1b3f9515af77a1 100644 --- a/src/components/monitor/monitor.css +++ b/src/components/monitor/monitor.css @@ -43,6 +43,7 @@ margin: 0 5px; border-radius: calc($space / 2); padding: 0 2px; + white-space: pre-wrap; transform: translateZ(0); /* Fixes flickering in Safari */ } @@ -53,6 +54,7 @@ text-align: center; color: white; font-size: 1rem; + white-space: pre-wrap; transform: translateZ(0); /* Fixes flickering in Safari */ } @@ -149,7 +151,7 @@ overflow: hidden; /* Don't let long values escape container */ text-overflow: ellipsis; user-select: text; /* Allow selecting list values for 2.0 compatibility, only relevant in player */ - white-space: nowrap; + white-space: pre; } .list-input { diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx index 2012c61e555cf8bf4a13160c430db09fea320e34..314c38893518b0a8e5a8bce6a847dc008a6ac5b6 100644 --- a/src/containers/gui.jsx +++ b/src/containers/gui.jsx @@ -4,14 +4,13 @@ import {compose} from 'redux'; import {connect} from 'react-redux'; import ReactModal from 'react-modal'; import VM from 'scratch-vm'; -import {defineMessages, injectIntl, intlShape} from 'react-intl'; +import {injectIntl, intlShape} from 'react-intl'; import ErrorBoundaryHOC from '../lib/error-boundary-hoc.jsx'; import { getIsError, getIsShowingProject } from '../reducers/project-state'; -import {setProjectTitle} from '../reducers/project-title'; import { activateTab, BLOCKS_TAB_INDEX, @@ -29,6 +28,7 @@ import { import FontLoaderHOC from '../lib/font-loader-hoc.jsx'; import LocalizationHOC from '../lib/localization-hoc.jsx'; import ProjectFetcherHOC from '../lib/project-fetcher-hoc.jsx'; +import TitledHOC from '../lib/titled-hoc.jsx'; import ProjectSaverHOC from '../lib/project-saver-hoc.jsx'; import QueryParserHOC from '../lib/query-parser-hoc.jsx'; import storage from '../lib/storage'; @@ -39,18 +39,9 @@ import cloudManagerHOC from '../lib/cloud-manager-hoc.jsx'; import GUIComponent from '../components/gui/gui.jsx'; import {setIsScratchDesktop} from '../lib/isScratchDesktop.js'; -const messages = defineMessages({ - defaultProjectTitle: { - id: 'gui.gui.defaultProjectTitle', - description: 'Default title for project', - defaultMessage: 'Scratch Project' - } -}); - class GUI extends React.Component { componentDidMount () { setIsScratchDesktop(this.props.isScratchDesktop); - this.setReduxTitle(this.props.projectTitle); this.props.onStorageInit(storage); this.props.onVmInit(this.props.vm); } @@ -58,24 +49,12 @@ class GUI extends React.Component { if (this.props.projectId !== prevProps.projectId && this.props.projectId !== null) { this.props.onUpdateProjectId(this.props.projectId); } - if (this.props.projectTitle !== prevProps.projectTitle) { - this.setReduxTitle(this.props.projectTitle); - } if (this.props.isShowingProject && !prevProps.isShowingProject) { // this only notifies container when a project changes from not yet loaded to loaded // At this time the project view in www doesn't need to know when a project is unloaded this.props.onProjectLoaded(); } } - setReduxTitle (newTitle) { - if (newTitle === null || typeof newTitle === 'undefined') { - this.props.onUpdateReduxProjectTitle( - this.props.intl.formatMessage(messages.defaultProjectTitle) - ); - } else { - this.props.onUpdateReduxProjectTitle(newTitle); - } - } render () { if (this.props.isError) { throw new Error( @@ -92,11 +71,9 @@ class GUI extends React.Component { onProjectLoaded, onStorageInit, onUpdateProjectId, - onUpdateReduxProjectTitle, onVmInit, projectHost, projectId, - projectTitle, /* eslint-enable no-unused-vars */ children, fetchingProject, @@ -131,12 +108,9 @@ GUI.propTypes = { onSeeCommunity: PropTypes.func, onStorageInit: PropTypes.func, onUpdateProjectId: PropTypes.func, - onUpdateProjectTitle: PropTypes.func, - onUpdateReduxProjectTitle: PropTypes.func, onVmInit: PropTypes.func, projectHost: PropTypes.string, projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - projectTitle: PropTypes.string, telemetryModalVisible: PropTypes.bool, vm: PropTypes.instanceOf(VM).isRequired }; @@ -186,8 +160,7 @@ const mapDispatchToProps = dispatch => ({ onActivateSoundsTab: () => dispatch(activateTab(SOUNDS_TAB_INDEX)), onRequestCloseBackdropLibrary: () => dispatch(closeBackdropLibrary()), onRequestCloseCostumeLibrary: () => dispatch(closeCostumeLibrary()), - onRequestCloseTelemetryModal: () => dispatch(closeTelemetryModal()), - onUpdateReduxProjectTitle: title => dispatch(setProjectTitle(title)) + onRequestCloseTelemetryModal: () => dispatch(closeTelemetryModal()) }); const ConnectedGUI = injectIntl(connect( @@ -204,6 +177,7 @@ const WrappedGui = compose( FontLoaderHOC, QueryParserHOC, ProjectFetcherHOC, + TitledHOC, ProjectSaverHOC, vmListenerHOC, vmManagerHOC, diff --git a/src/containers/sb-file-uploader.jsx b/src/containers/sb-file-uploader.jsx index ae5f4291536338a5b39f1a7be38a071bc95a2b9e..2019f719e978a9c485b540488f873cb8046644ee 100644 --- a/src/containers/sb-file-uploader.jsx +++ b/src/containers/sb-file-uploader.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import {connect} from 'react-redux'; import {defineMessages, injectIntl, intlShape} from 'react-intl'; +import {setProjectTitle} from '../reducers/project-title'; import log from '../lib/log'; import sharedMessages from '../lib/shared-messages'; @@ -131,7 +132,7 @@ class SBFileUploader extends React.Component { // This is necessary in case the user wants to reload a project if (filename) { const uploadedProjectTitle = this.getProjectTitleFromFilename(filename); - this.props.onUpdateProjectTitle(uploadedProjectTitle); + this.props.onReceivedProjectTitle(uploadedProjectTitle); } this.resetFileInput(); }) @@ -179,9 +180,9 @@ SBFileUploader.propTypes = { loadingState: PropTypes.oneOf(LoadingStates), onLoadingFinished: PropTypes.func, onLoadingStarted: PropTypes.func, - onUpdateProjectTitle: PropTypes.func, projectChanged: PropTypes.bool, requestProjectUpload: PropTypes.func, + onReceivedProjectTitle: PropTypes.func, userOwnsProject: PropTypes.bool, vm: PropTypes.shape({ loadProject: PropTypes.func @@ -209,7 +210,8 @@ const mapDispatchToProps = (dispatch, ownProps) => ({ dispatch(closeFileMenu()); }, requestProjectUpload: loadingState => dispatch(requestProjectUpload(loadingState)), - onLoadingStarted: () => dispatch(openLoadingProject()) + onLoadingStarted: () => dispatch(openLoadingProject()), + onReceivedProjectTitle: title => dispatch(setProjectTitle(title)) }); // Allow incoming props to override redux-provided props. Used to mock in tests. diff --git a/src/lib/libraries/decks/en-steps.js b/src/lib/libraries/decks/en-steps.js index ce74ef4c365866f4b31d8b6740f1a616461889f1..d9af8c33ed941d2bb35518d9809618e9993937cd 100644 --- a/src/lib/libraries/decks/en-steps.js +++ b/src/lib/libraries/decks/en-steps.js @@ -170,6 +170,34 @@ import moveArrowKeysUpDown from './steps/move-arrow-keys-up-down.en.png'; import glideAroundBackAndForth from './steps/glide-around-back-and-forth.en.png'; import glideAroundPoint from './steps/glide-around-point.en.png'; +// Code a Cartoon +import codeCartoonSaySomething from './steps/code-cartoon-01-say-something.en.png'; +import codeCartoonAnimate from './steps/code-cartoon-02-animate.en.gif'; +import codeCartoonSelectDifferentCharacter from './steps/code-cartoon-03-select-different-character.en.gif'; +import codeCartoonUseMinusSign from './steps/code-cartoon-04-use-minus-sign.en.gif'; +import codeCartoonGrowShrink from './steps/code-cartoon-05-grow-shrink.en.gif'; +import codeCartoonSelectDifferentCharacter2 from './steps/code-cartoon-06-select-another-different-character.en.gif'; +import codeCartoonJump from './steps/code-cartoon-07-jump.en.gif'; +import codeCartoonChangeScenes from './steps/code-cartoon-08-change-scenes.en.gif'; +import codeCartoonGlideAround from './steps/code-cartoon-09-glide-around.en.gif'; +import codeCartoonChangeCostumes from './steps/code-cartoon-10-change-costumes.en.gif'; +import codeCartoonChooseMoreCharacters from './steps/code-cartoon-11-choose-more-characters.en.jpg'; + +// Talking Tales +import talesAddExtension from './steps/talking-1-add-extension.en.gif'; +import talesChooseSprite from './steps/talking-2-choose-sprite.en.png'; +import talesSaySomething from './steps/talking-3-say-something.en.gif'; +import talesChooseBackdrop from './steps/talking-4-choose-backdrop.en.png'; +import talesSwitchBackdrop from './steps/talking-5-switch-backdrop.en.gif'; +import talesChooseAnotherSprite from './steps/talking-6-choose-another-sprite.en.png'; +import talesMoveAround from './steps/talking-7-move-around.en.gif'; +import talesChooseAnotherBackdrop from './steps/talking-8-choose-another-backdrop.en.png'; +import talesAnimateTalking from './steps/talking-9-animate.en.gif'; +import talesChooseThirdBackdrop from './steps/talking-10-choose-third-backdrop.en.png'; +import talesChooseSound from './steps/talking-11-choose-sound.en.gif'; +import talesDanceMoves from './steps/talking-12-dance-moves.en.gif'; +import talesAskAnswer from './steps/talking-13-ask-and-answer.en.gif'; + const enImages = { // Intro introMove: introMove, @@ -276,7 +304,7 @@ const enImages = { flyAddScenery: flyAddScenery, flyMoveScenery: flyMoveScenery, flySwitchLooks: flySwitchLooks, - + // Pong pongAddBackdrop: pongAddBackdrop, pongAddBallSprite: pongAddBallSprite, @@ -291,7 +319,7 @@ const enImages = { pongResetScore: pongResetScore, pongAddLineSprite: pongAddLineSprite, pongGameOver: pongGameOver, - + // Imagine a World imagineTypeWhatYouWant: imagineTypeWhatYouWant, imagineClickGreenFlag: imagineClickGreenFlag, @@ -308,26 +336,26 @@ const enImages = { imagineSwitchBackdrops: imagineSwitchBackdrops, imagineRecordASound: imagineRecordASound, imagineChooseSound: imagineChooseSound, - + // Add a Backdrop addBackdrop: addBackdrop, - + // Add Effects addEffects: addEffects, - + // Hide and Show hideAndShow: hideAndShow, - + // Switch Costumes switchCostumes: switchCostumes, - + // Change Size changeSize: changeSize, - + // Spin spinTurn: spinTurn, spinPointInDirection: spinPointInDirection, - + // Record a Sound recordASoundSoundsTab: recordASoundSoundsTab, recordASoundClickRecord: recordASoundClickRecord, @@ -341,9 +369,35 @@ const enImages = { // Glide Around glideAroundBackAndForth: glideAroundBackAndForth, - glideAroundPoint: glideAroundPoint - + glideAroundPoint: glideAroundPoint, + + // Code a Cartoon + codeCartoonSaySomething: codeCartoonSaySomething, + codeCartoonAnimate: codeCartoonAnimate, + codeCartoonSelectDifferentCharacter: codeCartoonSelectDifferentCharacter, + codeCartoonUseMinusSign: codeCartoonUseMinusSign, + codeCartoonGrowShrink: codeCartoonGrowShrink, + codeCartoonSelectDifferentCharacter2: codeCartoonSelectDifferentCharacter2, + codeCartoonJump: codeCartoonJump, + codeCartoonChangeScenes: codeCartoonChangeScenes, + codeCartoonGlideAround: codeCartoonGlideAround, + codeCartoonChangeCostumes: codeCartoonChangeCostumes, + codeCartoonChooseMoreCharacters: codeCartoonChooseMoreCharacters, + + // Talking Tales + talesAddExtension: talesAddExtension, + talesChooseSprite: talesChooseSprite, + talesSaySomething: talesSaySomething, + talesAskAnswer: talesAskAnswer, + talesChooseBackdrop: talesChooseBackdrop, + talesSwitchBackdrop: talesSwitchBackdrop, + talesChooseAnotherSprite: talesChooseAnotherSprite, + talesMoveAround: talesMoveAround, + talesChooseAnotherBackdrop: talesChooseAnotherBackdrop, + talesAnimateTalking: talesAnimateTalking, + talesChooseThirdBackdrop: talesChooseThirdBackdrop, + talesChooseSound: talesChooseSound, + talesDanceMoves: talesDanceMoves }; - export {enImages}; diff --git a/src/lib/libraries/decks/index.jsx b/src/lib/libraries/decks/index.jsx index b7412abdb6d8d7968f7db400c5b3375b1ef839aa..3e09346f1e1ac54893b241c5c42969f28d9d2537 100644 --- a/src/lib/libraries/decks/index.jsx +++ b/src/lib/libraries/decks/index.jsx @@ -45,6 +45,12 @@ import libraryPong from './thumbnails/pong.jpg'; // Imagine a World import libraryImagine from './thumbnails/imagine.jpg'; +// Code a Cartoon +import libraryCodeCartoon from './thumbnails/code-a-cartoon.jpg'; + +// Talking Tales +import libraryTalking from './thumbnails/talking.png'; + // Videos import recordASound from './thumbnails/record-a-sound.jpg'; import glideAroundThumb from './thumbnails/glide-around.jpg'; @@ -173,7 +179,7 @@ export default { ], urlId: 'name' }, - + 'imagine': { name: ( <FormattedMessage @@ -330,7 +336,7 @@ export default { ], urlId: 'imagine' }, - + 'Make-Music': { name: ( <FormattedMessage @@ -400,7 +406,7 @@ export default { ], urlId: 'music' }, - + 'Tell-A-Story': { name: ( <FormattedMessage @@ -513,7 +519,7 @@ export default { ], urlId: 'tell-a-story' }, - + 'Chase-Game': { name: ( <FormattedMessage @@ -711,7 +717,7 @@ export default { ], urlId: 'animate-a-character' }, - + 'Make-A-Game': { name: ( <FormattedMessage @@ -798,7 +804,7 @@ export default { ], urlId: 'clicker-game' }, - + 'make-it-fly': { name: ( <FormattedMessage @@ -928,7 +934,7 @@ export default { ], urlId: 'make-it-fly' }, - + 'pong': { name: ( <FormattedMessage @@ -1069,6 +1075,287 @@ export default { urlId: 'pong' }, + 'code-cartoon': { + name: ( + <FormattedMessage + defaultMessage="Code a Cartoon" + description="Name for the 'Code a Cartoon' how-to" + id="gui.howtos.code-cartoon" + /> + ), + tags: ['code-cartoon'], + requiredProjectId: '331474033', + img: libraryCodeCartoon, + steps: [{ + video: 'code-cartoon' + }, { + title: ( + <FormattedMessage + defaultMessage="Say Something When You Click the Green Flag" + description="Step name for 'Say Something When You Click the Green Flag' step" + id="gui.howtos.code-cartoon.step_codeCartoonSaySomething" + /> + ), + image: 'codeCartoonSaySomething' + }, { + title: ( + <FormattedMessage + defaultMessage="Animate a Character When You Click It" + description="Step name for 'Animate a Character When You Click It' step" + id="gui.howtos.code-cartoon.step_codeCartoonAnimate" + /> + ), + image: 'codeCartoonAnimate' + }, { + title: ( + <FormattedMessage + defaultMessage="Select a Different Character" + description="Step name for 'Select a Different Character' step" + id="gui.howtos.code-cartoon.step_codeCartoonSelectDifferentCharacter" + /> + ), + image: 'codeCartoonSelectDifferentCharacter' + }, { + title: ( + <FormattedMessage + defaultMessage="Use a Minus Sign to Get Smaller" + description="Step name for 'Use a Minus Sign to Get Smaller' step" + id="gui.howtos.code-cartoon.step_codeCartoonUseMinusSign" + /> + ), + image: 'codeCartoonUseMinusSign' + }, { + title: ( + <FormattedMessage + defaultMessage="Make a Character Grow and Shrink" + description="Step name for 'Make a Character Grow and Shrink' step" + id="gui.howtos.code-cartoon.step_codeCartoonGrowShrink" + /> + ), + image: 'codeCartoonGrowShrink' + }, { + title: ( + <FormattedMessage + defaultMessage="Select a Different Character" + description="Step name for 'Select a Different Character' step" + id="gui.howtos.code-cartoon.step_codeCartoonSelectDifferentCharacter2" + /> + ), + image: 'codeCartoonSelectDifferentCharacter2' + }, { + title: ( + <FormattedMessage + defaultMessage="Jump Up and Down" + description="Step name for 'Jump Up and Down' step" + id="gui.howtos.code-cartoon.step_codeCartoonJump" + /> + ), + image: 'codeCartoonJump' + }, { + title: ( + <FormattedMessage + defaultMessage="Click a Character to Change Scenes" + description="Step name for 'Click a Character to Change Scenes' step" + id="gui.howtos.code-cartoon.step_codeCartoonChangeScenes" + /> + ), + image: 'codeCartoonChangeScenes' + }, { + title: ( + <FormattedMessage + defaultMessage="Glide Around" + description="Step name for 'Glide Around' step" + id="gui.howtos.code-cartoon.step_codeCartoonGlideAround" + /> + ), + image: 'codeCartoonGlideAround' + }, { + title: ( + <FormattedMessage + defaultMessage="Change Costumes" + description="Step name for 'Change Costumes' step" + id="gui.howtos.code-cartoon.step_codeCartoonChangeCostumes" + /> + ), + image: 'codeCartoonChangeCostumes' + }, { + title: ( + <FormattedMessage + defaultMessage="Choose More Characters to Add to Your Cartoon" + description="Step name for 'Choose More Characters to Add to Your Cartoon' step" + id="gui.howtos.code-cartoon.step_codeCartoonChooseMoreCharacters" + /> + ), + image: 'codeCartoonChooseMoreCharacters' + }, { + deckIds: [ + 'Chase-Game', + 'Tell-A-Story' + ] + } + ], + urlId: 'code-cartoon' + }, + + 'cartoon-network': { + name: ( + <FormattedMessage + defaultMessage="Animate an Adventure Game" + description="Animate an Adventure Game' how-to" + id="gui.howtos.cartoon-network" + /> + ), + requiredProjectId: '249143200', + img: libraryCartoonNetwork, + steps: [{ + video: 'uz5oz5h9yg', + trackingPixel: ( + <img src="https://code.org/api/hour/begin_scratch_adventure.png" /> + ) + }, { + title: ( + <FormattedMessage + defaultMessage="Choose a Character to Show" + description="Step name for 'Choose a Character to Show' step" + id="gui.howtos.cartoon-network.step_CNcharacter" + /> + ), + image: 'cnShowCharacter' + }, { + title: ( + <FormattedMessage + defaultMessage="Say Something" + description="Step name for 'Say Something' step" + id="gui.howtos.cartoon-network.step_CNsay" + /> + ), + image: 'cnSay' + }, { + title: ( + <FormattedMessage + defaultMessage="Glide Around" + description="Step name for 'Glide Around' step" + id="gui.howtos.cartoon-network.step_CNglide" + /> + ), + image: 'cnGlide' + }, { + title: ( + <FormattedMessage + defaultMessage=" Choose an Object to Chase " + description="Step name for 'Choose an Object to Chase' step" + id="gui.howtos.cartoon-network.step_CNpicksprite" + /> + ), + image: 'cnPickSprite' + }, { + title: ( + <FormattedMessage + defaultMessage="Collect Objects" + description="Step name for 'Collect Objects' step" + id="gui.howtos.cartoon-network.step_CNcollect" + /> + ), + image: 'cnCollect' + }, { + title: ( + <FormattedMessage + defaultMessage="Make a Score Variable" + description="Step name for 'Make a Score Variable' step" + id="gui.howtos.cartoon-network.step_CNvariable" + /> + ), + image: 'cnVariable' + }, { + title: ( + <FormattedMessage + defaultMessage="Keep Score" + description="Step name for 'Keep Score' step" + id="gui.howtos.cartoon-network.step_CNscore" + /> + ), + image: 'cnScore' + }, { + title: ( + <FormattedMessage + defaultMessage="Level Up: Change Backdrop" + description="Step name for 'Level Up: Change Backdrop' step" + id="gui.howtos.cartoon-network.step_CNbackdrop" + /> + ), + image: 'cnBackdrop' + }, + { + video: '6o76f5ivo1' + }, + { + deckIds: [ + 'switch-costume', + 'add-effects' + ] + } + ], + urlId: 'animate-an-adventure-game' + }, + + 'Video-Sensing': { + name: ( + <FormattedMessage + defaultMessage="Video Sensing" + description="Name for the 'Video Sensing' how-to" + id="gui.howtos.videosens.name" + /> + ), + img: libraryVideoSens, + steps: [{ + video: '3pd1z110d6' + }, + { + title: ( + <FormattedMessage + defaultMessage="Add Extension" + description="Step name for 'Add Extension' step" + id="gui.howtos.videosens.step_addextension" + /> + ), + image: 'videoAddExtension' + }, { + title: ( + <FormattedMessage + defaultMessage="Pet the Cat" + description="Step name for 'Pet the Cat' step" + id="gui.howtos.videosens.step_pet" + /> + ), + image: 'videoPet' + }, { + title: ( + <FormattedMessage + defaultMessage="Animate" + description="Step name for 'Animate' step" + id="gui.howtos.videosens.step_animate" + /> + ), + image: 'videoAnimate' + }, { + title: ( + <FormattedMessage + defaultMessage="Pop a Balloon" + description="Step name for 'Pop a Balloon' step" + id="gui.howtos.videosens.step_pop" + /> + ), + image: 'videoPop' + }, { + deckIds: [ + 'Make-Music', + 'add-effects' + ] + } + ], + urlId: 'video-sensing' + }, + 'say-it-out-loud': { name: ( <FormattedMessage @@ -1183,163 +1470,143 @@ export default { urlId: 'animations-that-talk' }, - 'Video-Sensing': { + 'talking': { name: ( <FormattedMessage - defaultMessage="Video Sensing" - description="Name for the 'Video Sensing' how-to" - id="gui.howtos.videosens.name" + defaultMessage="Talking Tales" + description="Name for the 'Talking Tales' how-to" + id="gui.howtos.talking" /> ), - img: libraryVideoSens, + tags: ['talking'], + img: libraryTalking, steps: [{ - video: '3pd1z110d6' - }, - { + video: 'talking' + }, { title: ( <FormattedMessage - defaultMessage="Add Extension" - description="Step name for 'Add Extension' step" - id="gui.howtos.videosens.step_addextension" + defaultMessage="Click to Add the Text-to-Speech Blocks" + description="Step name for 'Click to Add the Text-to-Speech Blocks' step" + id="gui.howtos.talking.step_talesAddExtension" /> ), - image: 'videoAddExtension' + image: 'talesAddExtension' }, { title: ( <FormattedMessage - defaultMessage="Pet the Cat" - description="Step name for 'Pet the Cat' step" - id="gui.howtos.videosens.step_pet" + defaultMessage="Choose a Sprite" + description="Step name for 'Choose a Sprite' step" + id="gui.howtos.talking.step_talesChooseSprite" /> ), - image: 'videoPet' + image: 'talesChooseSprite' }, { title: ( <FormattedMessage - defaultMessage="Animate" - description="Step name for 'Animate' step" - id="gui.howtos.videosens.step_animate" + defaultMessage="Make a Character Speak" + description="Step name for 'Make a Character Speak' step" + id="gui.howtos.talking.step_talesSaySomething" /> ), - image: 'videoAnimate' + image: 'talesSaySomething' }, { title: ( <FormattedMessage - defaultMessage="Pop a Balloon" - description="Step name for 'Pop a Balloon' step" - id="gui.howtos.videosens.step_pop" + defaultMessage="Choose a Backdrop" + description="Step name for 'Choose a Backdrop' step" + id="gui.howtos.talking.step_talesChooseBackdrop" /> ), - image: 'videoPop' + image: 'talesChooseBackdrop' }, { - deckIds: [ - 'Make-Music', - 'add-effects' - ] - } - ], - urlId: 'video-sensing' - }, - - 'cartoon-network': { - name: ( - <FormattedMessage - defaultMessage="Animate an Adventure Game" - description="Animate an Adventure Game' how-to" - id="gui.howtos.cartoon-network" - /> - ), - requiredProjectId: '249143200', - img: libraryCartoonNetwork, - steps: [{ - video: 'uz5oz5h9yg', - trackingPixel: ( - <img src="https://code.org/api/hour/begin_scratch_adventure.png" /> - ) + title: ( + <FormattedMessage + defaultMessage="Click a Character to Go to the Next Backdrop" + description="Step name for 'Click a Character to Go to the Next Backdrop' step" + id="gui.howtos.talking.step_talesSwitchBackdrop" + /> + ), + image: 'talesSwitchBackdrop' }, { title: ( <FormattedMessage - defaultMessage="Choose a Character to Show" - description="Step name for 'Choose a Character to Show' step" - id="gui.howtos.cartoon-network.step_CNcharacter" + defaultMessage="Choose Another Sprite" + description="Step name for 'Choose Another Sprite' step" + id="gui.howtos.talking.step_talesChooseAnotherSprite" /> ), - image: 'cnShowCharacter' + image: 'talesChooseAnotherSprite' }, { title: ( <FormattedMessage - defaultMessage="Say Something" - description="Step name for 'Say Something' step" - id="gui.howtos.cartoon-network.step_CNsay" + defaultMessage="Move Around" + description="Step name for 'Move Around' step" + id="gui.howtos.talking.step_talesMoveAround" /> ), - image: 'cnSay' + image: 'talesMoveAround' }, { title: ( <FormattedMessage - defaultMessage="Glide Around" - description="Step name for 'Glide Around' step" - id="gui.howtos.cartoon-network.step_CNglide" + defaultMessage="Choose Another Backdrop" + description="Step name for 'Choose Another Backdrop' step" + id="gui.howtos.talking.step_talesChooseAnotherBackdrop" /> ), - image: 'cnGlide' + image: 'talesChooseAnotherBackdrop' }, { title: ( <FormattedMessage - defaultMessage=" Choose an Object to Chase " - description="Step name for 'Choose an Object to Chase' step" - id="gui.howtos.cartoon-network.step_CNpicksprite" + defaultMessage="Animate Talking" + description="Step name for 'Animate Talking' step" + id="gui.howtos.talking.step_talesAnimateTalking" /> ), - image: 'cnPickSprite' + image: 'talesAnimateTalking' }, { title: ( <FormattedMessage - defaultMessage="Collect Objects" - description="Step name for 'Collect Objects' step" - id="gui.howtos.cartoon-network.step_CNcollect" + defaultMessage="Choose Another Backdrop" + description="Step name for 'Choose Another Backdrop' step" + id="gui.howtos.talking.step_talesChooseThirdBackdrop" /> ), - image: 'cnCollect' + image: 'talesChooseThirdBackdrop' }, { title: ( <FormattedMessage - defaultMessage="Make a Score Variable" - description="Step name for 'Make a Score Variable' step" - id="gui.howtos.cartoon-network.step_CNvariable" + defaultMessage="Choose a Song to Dance To" + description="Step name for 'Choose a Song to Dance To' step" + id="gui.howtos.talking.step_talesChooseSound" /> ), - image: 'cnVariable' + image: 'talesChooseSound' }, { title: ( <FormattedMessage - defaultMessage="Keep Score" - description="Step name for 'Keep Score' step" - id="gui.howtos.cartoon-network.step_CNscore" + defaultMessage="Dance Moves" + description="Step name for 'Dance Moves' step" + id="gui.howtos.talking.step_talesDanceMoves" /> ), - image: 'cnScore' + image: 'talesDanceMoves' }, { title: ( <FormattedMessage - defaultMessage="Level Up: Change Backdrop" - description="Step name for 'Level Up: Change Backdrop' step" - id="gui.howtos.cartoon-network.step_CNbackdrop" + defaultMessage="Get the Ask and Answer Blocks from the Sensing Category" + description="Step name for 'Get the Ask and Answer Blocks from the Sensing Category' step" + id="gui.howtos.talking.step_talesAskAnswer" /> ), - image: 'cnBackdrop' - }, - { - video: '6o76f5ivo1' - }, - { + image: 'talesAskAnswer' + }, { deckIds: [ - 'switch-costume', - 'add-effects' + 'Tell-A-Story', + 'Animate-A-Character' ] } ], - urlId: 'animate-an-adventure-game' + urlId: 'talking' }, 'add-sprite': { @@ -1372,7 +1639,7 @@ export default { ], urlId: 'add-a-sprite' }, - + 'add-a-backdrop': { name: ( <FormattedMessage @@ -1404,7 +1671,7 @@ export default { }], urlId: 'add-a-backdrop' }, - + 'change-size': { name: ( <FormattedMessage @@ -1434,7 +1701,7 @@ export default { }], urlId: 'change-size' }, - + 'glide-around': { name: ( <FormattedMessage @@ -1539,7 +1806,7 @@ export default { }], urlId: 'record-a-sound' }, - + 'spin-video': { name: ( <FormattedMessage @@ -1578,7 +1845,7 @@ export default { }], urlId: 'make-it-spin' }, - + 'hide-and-show': { name: ( <FormattedMessage @@ -1677,7 +1944,7 @@ export default { }], urlId: 'arrow-keys' }, - + 'add-effects': { name: ( <FormattedMessage @@ -1708,7 +1975,7 @@ export default { }], urlId: 'add-effects' }, - + 'wedo2-getting-started': { steps: [{ video: '4im7iizv47' @@ -1716,7 +1983,7 @@ export default { urlId: 'wedo', hidden: true }, - + 'ev3-getting-started': { steps: [{ video: 'qgu78c5y7d' @@ -1724,7 +1991,7 @@ export default { urlId: 'ev3', hidden: true }, - + 'whats-new': { steps: [{ video: 'mtqymxg0qq' diff --git a/src/lib/libraries/decks/steps/code-cartoon-01-say-something.en.png b/src/lib/libraries/decks/steps/code-cartoon-01-say-something.en.png new file mode 100644 index 0000000000000000000000000000000000000000..f2a1570c3876d023b8e341c2a3910bb05b312f48 Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-01-say-something.en.png differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-02-animate.en.gif b/src/lib/libraries/decks/steps/code-cartoon-02-animate.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..801670c67ad47303ead6f49b238efaa14feb44f8 Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-02-animate.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-03-select-different-character.en.gif b/src/lib/libraries/decks/steps/code-cartoon-03-select-different-character.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..9881aac5d22c16cef25c4c15b53a20acdb7db13c Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-03-select-different-character.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-04-use-minus-sign.en.gif b/src/lib/libraries/decks/steps/code-cartoon-04-use-minus-sign.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..783384fc49fa624f915bebfea5b1773fdfda9ad7 Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-04-use-minus-sign.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-05-grow-shrink.en.gif b/src/lib/libraries/decks/steps/code-cartoon-05-grow-shrink.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..e4bbf5dad36d51c12dbe2f3db84f73057afd7ab8 Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-05-grow-shrink.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-06-select-another-different-character.en.gif b/src/lib/libraries/decks/steps/code-cartoon-06-select-another-different-character.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..6aa589a6751268a6ab05ad2e0027a78197992cf7 Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-06-select-another-different-character.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-07-jump.en.gif b/src/lib/libraries/decks/steps/code-cartoon-07-jump.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000306b208aacb70d19525dbc1cb98ce45d2cef Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-07-jump.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-08-change-scenes.en.gif b/src/lib/libraries/decks/steps/code-cartoon-08-change-scenes.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..fb27d72112262354de6227526994928158afa854 Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-08-change-scenes.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-09-glide-around.en.gif b/src/lib/libraries/decks/steps/code-cartoon-09-glide-around.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..2a63ac116b5258c76a1ced3e5f0c9660ad0de59c Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-09-glide-around.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-10-change-costumes.en.gif b/src/lib/libraries/decks/steps/code-cartoon-10-change-costumes.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..e521e45f3297044025c85885caf2abb4a81c1196 Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-10-change-costumes.en.gif differ diff --git a/src/lib/libraries/decks/steps/code-cartoon-11-choose-more-characters.en.jpg b/src/lib/libraries/decks/steps/code-cartoon-11-choose-more-characters.en.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a88acc29d7964f44c91d0d0de1dfa2f96b79d24 Binary files /dev/null and b/src/lib/libraries/decks/steps/code-cartoon-11-choose-more-characters.en.jpg differ diff --git a/src/lib/libraries/decks/steps/talking-1-add-extension.en.gif b/src/lib/libraries/decks/steps/talking-1-add-extension.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..b3e5b2f12d04b8cdd95e1ca1f1302df563536862 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-1-add-extension.en.gif differ diff --git a/src/lib/libraries/decks/steps/talking-10-choose-third-backdrop.en.png b/src/lib/libraries/decks/steps/talking-10-choose-third-backdrop.en.png new file mode 100755 index 0000000000000000000000000000000000000000..e266486bc283cd054a86be3e3c125ddb2e333da0 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-10-choose-third-backdrop.en.png differ diff --git a/src/lib/libraries/decks/steps/talking-11-choose-sound.en.gif b/src/lib/libraries/decks/steps/talking-11-choose-sound.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..8bec863371aaeffcae7a79abc4ff80d6953f6cc4 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-11-choose-sound.en.gif differ diff --git a/src/lib/libraries/decks/steps/talking-12-dance-moves.en.gif b/src/lib/libraries/decks/steps/talking-12-dance-moves.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..042935be889550d22f5aef5c8bd612e1d2796d95 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-12-dance-moves.en.gif differ diff --git a/src/lib/libraries/decks/steps/talking-13-ask-and-answer.en.gif b/src/lib/libraries/decks/steps/talking-13-ask-and-answer.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..78a5c2f9e611cd4a2b481b6cecf2388437e42c24 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-13-ask-and-answer.en.gif differ diff --git a/src/lib/libraries/decks/steps/talking-2-choose-sprite.en.png b/src/lib/libraries/decks/steps/talking-2-choose-sprite.en.png new file mode 100755 index 0000000000000000000000000000000000000000..9eeea61ad6ae2fea50704cf76f43bf077f77fcd9 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-2-choose-sprite.en.png differ diff --git a/src/lib/libraries/decks/steps/talking-3-say-something.en.gif b/src/lib/libraries/decks/steps/talking-3-say-something.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..19a1735cad219f0e34b026e9f8986f74a848b6e9 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-3-say-something.en.gif differ diff --git a/src/lib/libraries/decks/steps/talking-4-choose-backdrop.en.png b/src/lib/libraries/decks/steps/talking-4-choose-backdrop.en.png new file mode 100755 index 0000000000000000000000000000000000000000..6a2c8d72220921eeb22bc2bc30fe057c31203dd2 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-4-choose-backdrop.en.png differ diff --git a/src/lib/libraries/decks/steps/talking-5-switch-backdrop.en.gif b/src/lib/libraries/decks/steps/talking-5-switch-backdrop.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..6012a7303236d3b3a6bacfff6646427249ede3ac Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-5-switch-backdrop.en.gif differ diff --git a/src/lib/libraries/decks/steps/talking-6-choose-another-sprite.en.png b/src/lib/libraries/decks/steps/talking-6-choose-another-sprite.en.png new file mode 100755 index 0000000000000000000000000000000000000000..cf01d27558ad4f5b549cdc89b0dc93b9cb15e82e Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-6-choose-another-sprite.en.png differ diff --git a/src/lib/libraries/decks/steps/talking-7-move-around.en.gif b/src/lib/libraries/decks/steps/talking-7-move-around.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..025477326b98eedc316aa9f0497a3a5839bd877b Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-7-move-around.en.gif differ diff --git a/src/lib/libraries/decks/steps/talking-8-choose-another-backdrop.en.png b/src/lib/libraries/decks/steps/talking-8-choose-another-backdrop.en.png new file mode 100755 index 0000000000000000000000000000000000000000..607d8672c6bce91eecac2bf4e8bb330959102665 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-8-choose-another-backdrop.en.png differ diff --git a/src/lib/libraries/decks/steps/talking-9-animate.en.gif b/src/lib/libraries/decks/steps/talking-9-animate.en.gif new file mode 100644 index 0000000000000000000000000000000000000000..5e937abd75707b12bcd0408b704c1e2ae5c82795 Binary files /dev/null and b/src/lib/libraries/decks/steps/talking-9-animate.en.gif differ diff --git a/src/lib/libraries/decks/thumbnails/code-a-cartoon.jpg b/src/lib/libraries/decks/thumbnails/code-a-cartoon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b043b3f5e3374aef7b7a99f0a335cdde7a670387 Binary files /dev/null and b/src/lib/libraries/decks/thumbnails/code-a-cartoon.jpg differ diff --git a/src/lib/libraries/decks/thumbnails/talking.png b/src/lib/libraries/decks/thumbnails/talking.png new file mode 100644 index 0000000000000000000000000000000000000000..51c06c6ef009bd738a4d9725806a97aed64445a7 Binary files /dev/null and b/src/lib/libraries/decks/thumbnails/talking.png differ diff --git a/src/lib/libraries/decks/translate-video.js b/src/lib/libraries/decks/translate-video.js index 3a5e219c618bd8a3bf65ce09bd8da305435d9d4c..8b58c08da7d7960a06ce30576513d4a6bc11bf49 100644 --- a/src/lib/libraries/decks/translate-video.js +++ b/src/lib/libraries/decks/translate-video.js @@ -123,6 +123,12 @@ const videos = { }, 'imagine': { en: '1ndh08yiso' + }, + 'code-cartoon': { + en: 'fpfuky3x6g' + }, + 'talking': { + en: 'j0208mq4qi' } }; diff --git a/src/lib/titled-hoc.jsx b/src/lib/titled-hoc.jsx index 377d6150d2513ea1cf2bff65d2cd5cd35a08972d..6115990087deef53433ee043a9616e9ef4a499b4 100644 --- a/src/lib/titled-hoc.jsx +++ b/src/lib/titled-hoc.jsx @@ -1,5 +1,18 @@ +import PropTypes from 'prop-types'; import React from 'react'; -import bindAll from 'lodash.bindall'; +import {connect} from 'react-redux'; +import {defineMessages, injectIntl, intlShape} from 'react-intl'; + +import {getIsShowingWithoutId} from '../reducers/project-state'; +import {setProjectTitle} from '../reducers/project-title'; + +const messages = defineMessages({ + defaultProjectTitle: { + id: 'gui.gui.defaultProjectTitle', + description: 'Default title for project', + defaultMessage: 'Scratch Project' + } +}); /* Higher Order Component to get and set the project title * @param {React.Component} WrappedComponent component to receive project title related props @@ -7,31 +20,79 @@ import bindAll from 'lodash.bindall'; */ const TitledHOC = function (WrappedComponent) { class TitledComponent extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleUpdateProjectTitle' - ]); - this.state = { - projectTitle: null - }; + componentDidMount () { + this.handleReceivedProjectTitle(this.props.projectTitle); + } + componentDidUpdate (prevProps) { + if (this.props.projectTitle !== prevProps.projectTitle) { + this.handleReceivedProjectTitle(this.props.projectTitle); + } + // if the projectTitle hasn't changed, but the reduxProjectTitle + // HAS changed, we need to report that change to the projectTitle's owner + if (this.props.reduxProjectTitle !== prevProps.reduxProjectTitle && + this.props.reduxProjectTitle !== this.props.projectTitle) { + this.props.onUpdateProjectTitle(this.props.reduxProjectTitle); + } } - handleUpdateProjectTitle (newTitle) { - this.setState({projectTitle: newTitle}); + handleReceivedProjectTitle (requestedTitle) { + let newTitle = requestedTitle; + if (newTitle === null || typeof newTitle === 'undefined') { + newTitle = this.props.intl.formatMessage(messages.defaultProjectTitle); + } + this.props.onChangedProjectTitle(newTitle); } render () { + const { + /* eslint-disable no-unused-vars */ + intl, + isShowingWithoutId, + onChangedProjectTitle, + // for children, we replace onUpdateProjectTitle with our own + onUpdateProjectTitle, + // we don't pass projectTitle prop to children -- they must use + // redux value + projectTitle, + reduxProjectTitle, + /* eslint-enable no-unused-vars */ + ...componentProps + } = this.props; return ( <WrappedComponent - canEditTitle - projectTitle={this.state.projectTitle} - onUpdateProjectTitle={this.handleUpdateProjectTitle} - {...this.props} + {...componentProps} /> ); } } - return TitledComponent; + TitledComponent.propTypes = { + intl: intlShape, + isShowingWithoutId: PropTypes.bool, + onChangedProjectTitle: PropTypes.func, + onUpdateProjectTitle: PropTypes.func, + projectTitle: PropTypes.string, + reduxProjectTitle: PropTypes.string + }; + + TitledComponent.defaultProps = { + onUpdateProjectTitle: () => {} + }; + + const mapStateToProps = state => { + const loadingState = state.scratchGui.projectState.loadingState; + return { + isShowingWithoutId: getIsShowingWithoutId(loadingState), + reduxProjectTitle: state.scratchGui.projectTitle + }; + }; + + const mapDispatchToProps = dispatch => ({ + onChangedProjectTitle: title => dispatch(setProjectTitle(title)) + }); + + return injectIntl(connect( + mapStateToProps, + mapDispatchToProps, + )(TitledComponent)); }; export { diff --git a/src/playground/player.jsx b/src/playground/player.jsx index 8224ad6489c57ce5b071704de1adcdb776345b95..ae4cba1c9e7c39f43f5fba45c1763f8ce3a9f1b1 100644 --- a/src/playground/player.jsx +++ b/src/playground/player.jsx @@ -9,7 +9,6 @@ import Box from '../components/box/box.jsx'; import GUI from '../containers/gui.jsx'; import HashParserHOC from '../lib/hash-parser-hoc.jsx'; import AppStateHOC from '../lib/app-state-hoc.jsx'; -import TitledHOC from '../lib/titled-hoc.jsx'; import {setPlayer} from '../reducers/mode'; @@ -24,6 +23,7 @@ const Player = ({isPlayerOnly, onSeeInside, projectId}) => ( <Box className={classNames(isPlayerOnly ? styles.stageOnly : styles.editor)}> {isPlayerOnly && <button onClick={onSeeInside}>{'See inside'}</button>} <GUI + canEditTitle enableCommunity isPlayerOnly={isPlayerOnly} projectId={projectId} @@ -55,8 +55,7 @@ const ConnectedPlayer = connect( // ability to compose reducers. const WrappedPlayer = compose( AppStateHOC, - HashParserHOC, - TitledHOC + HashParserHOC )(ConnectedPlayer); const appTarget = document.createElement('div'); diff --git a/src/playground/render-gui.jsx b/src/playground/render-gui.jsx index 78a79b6ee1f60981ea264a8b9670fca6ec017934..0f15fbfa707f322c7d478e56cfb590debdc00a42 100644 --- a/src/playground/render-gui.jsx +++ b/src/playground/render-gui.jsx @@ -5,7 +5,6 @@ import {compose} from 'redux'; import AppStateHOC from '../lib/app-state-hoc.jsx'; import GUI from '../containers/gui.jsx'; import HashParserHOC from '../lib/hash-parser-hoc.jsx'; -import TitledHOC from '../lib/titled-hoc.jsx'; import log from '../lib/log.js'; const onClickLogo = () => { @@ -37,8 +36,7 @@ export default appTarget => { // ability to compose reducers. const WrappedGui = compose( AppStateHOC, - HashParserHOC, - TitledHOC + HashParserHOC )(GUI); // TODO a hack for testing the backpack, allow backpack host to be set by url param @@ -67,6 +65,7 @@ export default appTarget => { // important: this is checking whether `simulateScratchDesktop` is truthy, not just defined! simulateScratchDesktop ? <WrappedGui + canEditTitle isScratchDesktop showTelemetryModal canSave={false} @@ -75,6 +74,7 @@ export default appTarget => { onTelemetryModalOptOut={handleTelemetryModalOptOut} /> : <WrappedGui + canEditTitle backpackVisible showComingSoon backpackHost={backpackHost} diff --git a/test/helpers/selenium-helper.js b/test/helpers/selenium-helper.js index 1072cb0d6f33d0f551de1d47cab392361ca183c7..84e6c355ae460a2580f3093035de9c6c8e6918e9 100644 --- a/test/helpers/selenium-helper.js +++ b/test/helpers/selenium-helper.js @@ -57,6 +57,10 @@ class SeleniumHelper { // Stub getUserMedia to always not allow access args.push('--use-fake-ui-for-media-stream=deny'); + // Suppress complaints about AudioContext starting before a user gesture + // This is especially important on Windows, where Selenium directs JS console messages to stdout + args.push('--autoplay-policy=no-user-gesture-required'); + chromeCapabilities.set('chromeOptions', {args}); chromeCapabilities.setLoggingPrefs({ performance: 'ALL' diff --git a/test/unit/containers/sb-file-uploader.test.jsx b/test/unit/containers/sb-file-uploader.test.jsx index 083dbfa2da12f4d3a7c946ea54e0e26b00518553..c757114b4ca7e387c78e7477931cf31a04c91a9a 100644 --- a/test/unit/containers/sb-file-uploader.test.jsx +++ b/test/unit/containers/sb-file-uploader.test.jsx @@ -11,7 +11,6 @@ describe('SBFileUploader Container', () => { const mockStore = configureStore(); let onLoadingFinished; let onLoadingStarted; - let onUpdateProjectTitle; let store; // Wrap this in a function so it gets test specific states and can be reused. @@ -20,7 +19,6 @@ describe('SBFileUploader Container', () => { <SBFileUploader onLoadingFinished={onLoadingFinished} onLoadingStarted={onLoadingStarted} - onUpdateProjectTitle={onUpdateProjectTitle} > {(renderFileInput, loadProject) => ( <div @@ -40,7 +38,6 @@ describe('SBFileUploader Container', () => { vm: {} } }); - onUpdateProjectTitle = jest.fn(); onLoadingFinished = jest.fn(); onLoadingStarted = jest.fn(); }); diff --git a/webpack.config.js b/webpack.config.js index b134cd09014339f4a8558dc5db42467b1693ddc7..283d65706b5581768180d92d16cdd70c4ed847d9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -219,6 +219,12 @@ module.exports = [ new CopyWebpackPlugin([{ from: 'extension-worker.{js,js.map}', context: 'node_modules/scratch-vm/dist/web' + }]), + // Include library JSON files for scratch-desktop to use for downloading + new CopyWebpackPlugin([{ + from: 'src/lib/libraries/*.json', + to: 'libraries', + flatten: true }]) ]) })) : []