diff --git a/.npmignore b/.npmignore index 61247064a..dee8a6a5d 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 38af9f8b2..2a9152628 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 9d1229dec..dd51feeb2 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 de3cfdeff..121d3432a 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 3c68eec90..9846eed75 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} /> @@ -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 1fa7a01cc..98bc128a9 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 { {(className, renderFileInput, handleLoadProject) => ( @@ -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 b9b5aa6d8..fe7647cb0 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 ( - - ); - } -} +const ProjectTitleInput = ({ + className, + intl, + onSubmit, + projectTitle +}) => ( + +); 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 97a62e02d..521c39279 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 2012c61e5..314c38893 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 ae5f42915..2019f719e 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 ce74ef4c3..d9af8c33e 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 b7412abdb..3e09346f1 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: ( + ), + tags: ['code-cartoon'], + requiredProjectId: '331474033', + img: libraryCodeCartoon, + steps: [{ + video: 'code-cartoon' + }, { + title: ( + + ), + image: 'codeCartoonSaySomething' + }, { + title: ( + + ), + image: 'codeCartoonAnimate' + }, { + title: ( + + ), + image: 'codeCartoonSelectDifferentCharacter' + }, { + title: ( + + ), + image: 'codeCartoonUseMinusSign' + }, { + title: ( + + ), + image: 'codeCartoonGrowShrink' + }, { + title: ( + + ), + image: 'codeCartoonSelectDifferentCharacter2' + }, { + title: ( + + ), + image: 'codeCartoonJump' + }, { + title: ( + + ), + image: 'codeCartoonChangeScenes' + }, { + title: ( + + ), + image: 'codeCartoonGlideAround' + }, { + title: ( + + ), + image: 'codeCartoonChangeCostumes' + }, { + title: ( + + ), + image: 'codeCartoonChooseMoreCharacters' + }, { + deckIds: [ + 'Chase-Game', + 'Tell-A-Story' + ] + } + ], + urlId: 'code-cartoon' + }, + + 'cartoon-network': { + name: ( + + ), + requiredProjectId: '249143200', + img: libraryCartoonNetwork, + steps: [{ + video: 'uz5oz5h9yg', + trackingPixel: ( + + ) + }, { + title: ( + + ), + image: 'cnShowCharacter' + }, { + title: ( + + ), + image: 'cnSay' + }, { + title: ( + + ), + image: 'cnGlide' + }, { + title: ( + + ), + image: 'cnPickSprite' + }, { + title: ( + + ), + image: 'cnCollect' + }, { + title: ( + + ), + image: 'cnVariable' + }, { + title: ( + + ), + image: 'cnScore' + }, { + title: ( + + ), + image: 'cnBackdrop' + }, + { + video: '6o76f5ivo1' + }, + { + deckIds: [ + 'switch-costume', + 'add-effects' + ] + } + ], + urlId: 'animate-an-adventure-game' + }, + + 'Video-Sensing': { + name: ( + + ), + img: libraryVideoSens, + steps: [{ + video: '3pd1z110d6' + }, + { + title: ( + + ), + image: 'videoAddExtension' + }, { + title: ( + + ), + image: 'videoPet' + }, { + title: ( + + ), + image: 'videoAnimate' + }, { + title: ( + + ), + image: 'videoPop' + }, { + deckIds: [ + 'Make-Music', + 'add-effects' + ] + } + ], + urlId: 'video-sensing' + }, + 'say-it-out-loud': { name: ( ), - img: libraryVideoSens, + tags: ['talking'], + img: libraryTalking, steps: [{ - video: '3pd1z110d6' - }, - { - title: ( - - ), - image: 'videoAddExtension' + video: 'talking' }, { title: ( ), - image: 'videoPet' + image: 'talesAddExtension' }, { title: ( ), - image: 'videoAnimate' + image: 'talesChooseSprite' }, { title: ( ), - image: 'videoPop' + image: 'talesSaySomething' + }, { + title: ( + + ), + image: 'talesChooseBackdrop' + }, { + title: ( + + ), + image: 'talesSwitchBackdrop' + }, { + title: ( + + ), + image: 'talesChooseAnotherSprite' + }, { + title: ( + + ), + image: 'talesMoveAround' + }, { + title: ( + + ), + image: 'talesChooseAnotherBackdrop' + }, { + title: ( + + ), + image: 'talesAnimateTalking' + }, { + title: ( + + ), + image: 'talesChooseThirdBackdrop' + }, { + title: ( + + ), + image: 'talesChooseSound' + }, { + title: ( + + ), + image: 'talesDanceMoves' + }, { + title: ( + + ), + image: 'talesAskAnswer' }, { deckIds: [ - 'Make-Music', - 'add-effects' + 'Tell-A-Story', + 'Animate-A-Character' ] } ], - urlId: 'video-sensing' - }, - - 'cartoon-network': { - name: ( - - ), - requiredProjectId: '249143200', - img: libraryCartoonNetwork, - steps: [{ - video: 'uz5oz5h9yg', - trackingPixel: ( - - ) - }, { - title: ( - - ), - image: 'cnShowCharacter' - }, { - title: ( - - ), - image: 'cnSay' - }, { - title: ( - - ), - image: 'cnGlide' - }, { - title: ( - - ), - image: 'cnPickSprite' - }, { - title: ( - - ), - image: 'cnCollect' - }, { - title: ( - - ), - image: 'cnVariable' - }, { - title: ( - - ), - image: 'cnScore' - }, { - title: ( - - ), - image: 'cnBackdrop' - }, - { - video: '6o76f5ivo1' - }, - { - deckIds: [ - 'switch-costume', - 'add-effects' - ] - } - ], - urlId: 'animate-an-adventure-game' + urlId: 'talking' }, 'add-sprite': { @@ -1372,7 +1639,7 @@ export default { ], urlId: 'add-a-sprite' }, - + 'add-a-backdrop': { name: ( ); } } - 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 8224ad648..ae4cba1c9 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}) => ( {isPlayerOnly && } { @@ -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 ? { onTelemetryModalOptOut={handleTelemetryModalOptOut} /> : { 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', () => { {(renderFileInput, loadProject) => (
{ vm: {} } }); - onUpdateProjectTitle = jest.fn(); onLoadingFinished = jest.fn(); onLoadingStarted = jest.fn(); }); diff --git a/webpack.config.js b/webpack.config.js index b134cd090..283d65706 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 }]) ]) })) : []