diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a13f031d4d..fa11f3cbc0a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -136,18 +136,15 @@ jobs: - *restore_dist_cache - checkout - run: | - echo export RELEASE_VERSION="0.1.0-prerelease.$(date +'%Y%m%d%H%M%S')" >> $BASH_ENV + echo export RELEASE_VERSION="0.1.0-raspberrypifoundation.$(date +'%Y%m%d%H%M%S')" >> $BASH_ENV echo export NPM_TAG=latest >> $BASH_ENV - if [ "$CIRCLE_BRANCH" == "master" ] - then echo export NPM_TAG=stable >> $BASH_ENV - fi - if [[ "$CIRCLE_BRANCH" == hotfix/* ]] # double brackets are important for matching the wildcard - then echo export NPM_TAG=hotfix >> $BASH_ENV - fi - run: npm version --no-git-tag-version $RELEASE_VERSION - run: | npm set //registry.npmjs.org/:_authToken=$NPM_TOKEN - npm publish --tag $NPM_TAG + npm publish --access public --tag $NPM_TAG + - add_ssh_keys: + fingerprints: + - "27:82:d3:24:48:41:aa:7c:94:40:54:d9:1e:43:d2:9b" - run: git tag $RELEASE_VERSION - run: git push $CIRCLE_REPOSITORY_URL $RELEASE_VERSION @@ -158,35 +155,16 @@ jobs: - checkout - *restore_npm_cache - *restore_build_cache + - add_ssh_keys: + fingerprints: + - "27:82:d3:24:48:41:aa:7c:94:40:54:d9:1e:43:d2:9b" - run: | git config --global user.email $(git log --pretty=format:"%ae" -n1) git config --global user.name $(git log --pretty=format:"%an" -n1) - run: npm run deploy -- -e $CIRCLE_BRANCH - push-translations: - <<: *defaults - steps: - - *restore_git_cache - - checkout - - *restore_npm_cache - - run: npm run i18n:src - - run: npm run i18n:push workflows: version: 2 - push-translations: - triggers: - - schedule: - cron: 0 0 * * * # daily at 12 UTC, 8 ET - filters: - branches: - only: - - develop - jobs: - - setup - - push-translations: - requires: - - setup - build-test-deploy: jobs: - setup @@ -217,9 +195,7 @@ workflows: filters: branches: only: - - master - - develop - - /^hotfix\/.*/ + - code-club-world - deploy-gh-pages: requires: - lint diff --git a/README.md b/README.md index 3717731e189..9f592c652d7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,20 @@ # scratch-gui #### Scratch GUI is a set of React components that comprise the interface for creating and running Scratch 3.0 projects +## Raspberry Pi Foundation customisation + +[![CircleCI status of RaspberryPiFoundation/scratch-gui](https://circleci.com/gh/RaspberryPiFoundation/scratch-gui.svg?style=shield&circle-token=d6d268de56c55a3e520e59195047105029345eaf)](https://app.circleci.com/pipelines/github/RaspberryPiFoundation/scratch-gui?branch=code-club-world) + +* This is a fork of [the canonical repo](https://github.com/LLK/scratch-gui.git) to allow us to customise it for the [Code Club World app](https://github.com/RaspberryPiFoundation/codeclubworld). + +* The default branch of the canonical repo is `develop`, but the default branch of this repo is `code-club-world`. This is to make it clear that the latter is where we should be making changes, to make it easier to bring in changes from the upstream repo, and so we can have our own CircleCI configuration to automatically build the app. + +* Commits pushed to the forked repo on GitHub trigger [builds on CircleCI](https://app.circleci.com/pipelines/github/RaspberryPiFoundation/scratch-gui) and a successful build results in the build output being deployed to GitHub Pages for this repo and a version of the package being published to [the npm registry](https://www.npmjs.com/). The deployment makes use of an SSH key with write access to this repo. + +* The deployment adds the build output to the `gh-pages` branch in a sub-directory with the same name as the current branch. Thus the app is available at a URL including that sub-directory, e.g. https://raspberrypifoundation.github.io/scratch-gui/code-club-world/ for the default `code-club-world` branch. + +* The deployment publishes an organisation-scoped version of the package: [`@raspberrypifoundation/scratch-gui`](https://www.npmjs.com/package/@raspberrypifoundation/scratch-gui). The publishing of the package makes use of an access token set as an environment variable (`NPM_TOKEN`) in the CircleCI project settings. The git repo is also tagged with the release version. + ## Installation This requires you to have Git and Node.js installed. diff --git a/package-lock.json b/package-lock.json index 4fb45d7a120..23e03d9977c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "scratch-gui", + "name": "@raspberrypifoundation/scratch-gui", "version": "0.1.0", "lockfileVersion": 1, "requires": true, diff --git a/package.json b/package.json index 5c9217b0667..5356db91e05 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "scratch-gui", + "name": "@raspberrypifoundation/scratch-gui", "version": "0.1.0", "description": "GraphicaL User Interface for creating and running Scratch 3.0 projects", "main": "./dist/scratch-gui.js", @@ -20,10 +20,10 @@ }, "author": "Massachusetts Institute of Technology", "license": "BSD-3-Clause", - "homepage": "https://github.com/LLK/scratch-gui#readme", + "homepage": "https://github.com/RaspberryPiFoundation/scratch-gui#readme", "repository": { "type": "git", - "url": "git+ssh://git@github.com/LLK/scratch-gui.git" + "url": "git+ssh://git@github.com/RaspberryPiFoundation/scratch-gui.git" }, "dependencies": { "arraybuffer-loader": "^1.0.6", diff --git a/src/components/gui/gui.css b/src/components/gui/gui.css index eeb3989a1fe..565e55b8000 100644 --- a/src/components/gui/gui.css +++ b/src/components/gui/gui.css @@ -7,8 +7,12 @@ } .body-wrapper { - height: calc(100% - $menu-bar-height); background-color: $ui-primary; + height: calc(100% - $menu-bar-height); +} + +.body-wrapper-without-menu-bar { + height: 100%; } .body-wrapper * { diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index a446048989c..a4b50860867 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -89,6 +89,7 @@ const GUIComponent = props => { isTelemetryEnabled, loading, logo, + menuBarHidden, renderLogin, onClickAbout, onClickAccountNav, @@ -140,6 +141,9 @@ const GUIComponent = props => { return ({isFullSize => { const stageSize = resolveStageSize(stageSizeMode, isFullSize); + const boxStyles = classNames(styles.bodyWrapper, { + [styles.bodyWrapperWithoutMenuBar]: menuBarHidden + }); return isPlayerOnly ? ( { onRequestClose={onRequestCloseBackdropLibrary} /> ) : null} - - + {!menuBarHidden && + + } + { {'Code { {'Costumes {targetIsStage ? ( { {'Sounds { className={styles.extensionButtonIcon} draggable={false} src={addExtensionIcon} + alt={'Add extension icon'} /> @@ -395,6 +405,7 @@ GUIComponent.propTypes = { isShared: PropTypes.bool, loading: PropTypes.bool, logo: PropTypes.string, + menuBarHidden: PropTypes.bool, onActivateCostumesTab: PropTypes.func, onActivateSoundsTab: PropTypes.func, onActivateTab: PropTypes.func, @@ -442,6 +453,7 @@ GUIComponent.defaultProps = { isCreating: false, isShared: false, loading: false, + menuBarHidden: false, showComingSoon: false, stageSizeMode: STAGE_SIZE_MODES.large }; diff --git a/src/components/sprite-selector/sprite-list.jsx b/src/components/sprite-selector/sprite-list.jsx index 3d191029345..3ced6902a16 100644 --- a/src/components/sprite-selector/sprite-list.jsx +++ b/src/components/sprite-selector/sprite-list.jsx @@ -111,7 +111,7 @@ SpriteList.propTypes = { hoveredTarget: PropTypes.shape({ hoveredSprite: PropTypes.string, receivedBlocks: PropTypes.bool, - sprite: PropTypes.string + sprite: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), items: PropTypes.arrayOf(PropTypes.shape({ costume: PropTypes.shape({ diff --git a/src/containers/sprite-selector-item.jsx b/src/containers/sprite-selector-item.jsx index f946cf83f1d..1267e19d33d 100644 --- a/src/containers/sprite-selector-item.jsx +++ b/src/containers/sprite-selector-item.jsx @@ -151,7 +151,11 @@ SpriteSelectorItem.propTypes = { asset: PropTypes.instanceOf(storage.Asset), costumeURL: PropTypes.string, dispatchSetHoveredSprite: PropTypes.func.isRequired, - dragPayload: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + dragPayload: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.object + ]), dragType: PropTypes.string, dragging: PropTypes.bool, id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), diff --git a/src/css/colors.css b/src/css/colors.css index 6f38510e254..fb71c5d5712 100644 --- a/src/css/colors.css +++ b/src/css/colors.css @@ -14,7 +14,7 @@ $ui-black-transparent: hsla(0, 0%, 0%, 0.15); /* 15% transparent version of blac $text-primary: hsla(225, 15%, 40%, 1); /* #575E75 */ $text-primary-transparent: hsla(225, 15%, 40%, 0.75); -$motion-primary: hsla(215, 100%, 65%, 1); /* #4C97FF */ +$motion-primary: hsla(215, 60%, 50%, 1); /* #3373CC */ $motion-tertiary: hsla(215, 60%, 50%, 1); /* #3373CC */ $motion-transparent: hsla(215, 100%, 65%, 0.35); /* 35% transparent version of motion-primary */ $motion-light-transparent: hsla(215, 100%, 65%, 0.15); /* 15% transparent version of motion-primary */ diff --git a/src/index.js b/src/index.js index 70dda5a90ca..6153742a3c6 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import {ScratchPaintReducer} from 'scratch-paint'; import {setFullScreen, setPlayer} from './reducers/mode'; import {remixProject} from './reducers/project-state'; import {setAppElement} from 'react-modal'; +import saveProjectToServer from './lib/save-project-to-server'; const guiReducers = { locales: LocalesReducer, @@ -27,5 +28,6 @@ export { localesInitialState, remixProject, setFullScreen, - setPlayer + setPlayer, + saveProjectToServer }; diff --git a/src/lib/save-project-to-server.js b/src/lib/save-project-to-server.js index 2584923e60d..a9c04c369a5 100644 --- a/src/lib/save-project-to-server.js +++ b/src/lib/save-project-to-server.js @@ -12,15 +12,14 @@ import storage from '../lib/storage'; * @property {?boolean} params.isCopy a flag indicating if this save is creating a copy. * @property {?boolean} params.isRemix a flag indicating if this save is creating a remix. * @property {?string} params.title the title of the project. + * @param {object} headers extra HTTP request headers. * @return {Promise} A promise that resolves when the network request resolves. */ -export default function (projectId, vmState, params) { +export default function (projectId, vmState, params, headers) { const opts = { body: vmState, // If we set json:true then the body is double-stringified, so don't - headers: { - 'Content-Type': 'application/json' - }, + headers: Object.assign({'Content-Type': 'application/json'}, headers), withCredentials: true }; const creatingProject = projectId === null || typeof projectId === 'undefined';