From d1420862eadc42a41d12c32b8ed9b8fb512f99d5 Mon Sep 17 00:00:00 2001 From: chrisgarrity Date: Wed, 2 May 2018 15:27:49 -0400 Subject: [PATCH] Initial GUI embed (#1869) - `/preview/editor` will load GUI with an empty project - `/preview/:id/editor` will load GUI with a project from the projects server (not local data) - passes intl object to GUI - `/preview/:id` with show the project page with an embedded player - `/preview/:id/fullscreen` will load the project page with the player in fullscreen mode. * Note that we needed to Increase memory for the build to avoid running out of heap space, and build time increases by about 2 minutes --- Makefile | 6 +- package.json | 1 + src/routes.json | 2 +- src/views/preview/presentation.jsx | 26 +++++-- src/views/preview/preview.jsx | 114 +++++++++++++++++++---------- src/views/preview/preview.scss | 28 +++---- webpack.config.js | 16 +++- 7 files changed, 129 insertions(+), 64 deletions(-) diff --git a/Makefile b/Makefile index 65a57a3ac..cb2c10c9e 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ ESLINT=./node_modules/.bin/eslint -NODE=node +NODE= NODE_OPTIONS=--max_old_space_size=8000 node SASSLINT=./node_modules/.bin/sass-lint -v S3CMD=s3cmd sync -P --delete-removed --add-header=Cache-Control:no-cache,public,max-age=3600 TAP=./node_modules/.bin/tap -WATCH=./node_modules/.bin/watch -WEBPACK=./node_modules/.bin/webpack +WATCH= NODE_OPTIONS=--max_old_space_size=8000 ./node_modules/.bin/watch +WEBPACK= NODE_OPTIONS=--max_old_space_size=8000 ./node_modules/.bin/webpack # ------------------------------------ diff --git a/package.json b/package.json index 17e42e9c8..fec54dc38 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "redux-thunk": "2.0.1", "sass-lint": "1.5.1", "sass-loader": "6.0.6", + "scratch-gui": "0.1.0-prerelease.20180427201459", "scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master", "slick-carousel": "1.6.0", "source-map-support": "0.3.2", diff --git a/src/routes.json b/src/routes.json index fe9a1d8b3..5a6e7fedb 100644 --- a/src/routes.json +++ b/src/routes.json @@ -193,7 +193,7 @@ }, { "name": "preview", - "pattern": "^/preview/?(\\d+)?/?$", + "pattern": "^/preview/(*)/?$", "routeAlias": "/preview/?$", "view": "preview/preview", "title": "Scratch 3.0 Preview" diff --git a/src/views/preview/presentation.jsx b/src/views/preview/presentation.jsx index 8765ffe60..79df3f93b 100644 --- a/src/views/preview/presentation.jsx +++ b/src/views/preview/presentation.jsx @@ -6,12 +6,14 @@ const React = require('react'); const Formsy = require('formsy-react').default; const classNames = require('classnames'); +const GUI = require('scratch-gui').default; +const IntlGUI = injectIntl(GUI); + const sessionActions = require('../../redux/session.js'); const decorateText = require('../../lib/decorate-text.jsx'); const FlexRow = require('../../components/flex-row/flex-row.jsx'); const Avatar = require('../../components/avatar/avatar.jsx'); const CappedNumber = require('../../components/cappednumber/cappednumber.jsx'); -const placeholder = require('./gui-placeholder.png'); const ShareBanner = require('../../components/share-banner/share-banner.jsx'); const ThumbnailColumn = require('../../components/thumbnailcolumn/thumbnailcolumn.jsx'); const InplaceInput = require('../../components/forms/inplace-input.jsx'); @@ -25,8 +27,10 @@ const PreviewPresentation = props => { faved, favoriteCount, intl, + isFullScreen, loved, loveCount, + projectId, projectInfo, remixes, sessionStatus, @@ -34,6 +38,7 @@ const PreviewPresentation = props => { user, onFavoriteClicked, onLoveClicked, + onSeeInside, onUpdate // ...otherProps TBD } = props; @@ -93,15 +98,23 @@ const PreviewPresentation = props => { Remix } - -
- -
+ {shareDate && (
@@ -286,11 +299,14 @@ PreviewPresentation.propTypes = { faved: PropTypes.bool, favoriteCount: PropTypes.number, intl: intlShape, + isFullScreen: PropTypes.bool, loveCount: PropTypes.number, loved: PropTypes.bool, onFavoriteClicked: PropTypes.func, onLoveClicked: PropTypes.func, + onSeeInside: PropTypes.func, onUpdate: PropTypes.func, + projectId: PropTypes.number, projectInfo: PropTypes.shape({ id: PropTypes.number, title: PropTypes.string, diff --git a/src/views/preview/preview.jsx b/src/views/preview/preview.jsx index bc627b24f..426527846 100644 --- a/src/views/preview/preview.jsx +++ b/src/views/preview/preview.jsx @@ -2,6 +2,7 @@ const bindAll = require('lodash.bindall'); const React = require('react'); const PropTypes = require('prop-types'); const connect = require('react-redux').connect; +const injectIntl = require('react-intl').injectIntl; const Page = require('../../components/page/www/page.jsx'); const render = require('../../lib/render.jsx'); @@ -9,6 +10,8 @@ const PreviewPresentation = require('./presentation.jsx'); const sessionActions = require('../../redux/session.js'); const previewActions = require('../../redux/preview.js'); +const GUI = require('scratch-gui').default; +const IntlGUI = injectIntl(GUI); class Preview extends React.Component { constructor (props) { @@ -17,36 +20,28 @@ class Preview extends React.Component { 'handleFavoriteToggle', 'handleLoveToggle', 'handlePermissions', + 'handleSeeInside', 'handleUpdate', 'initCounts' ]); - this.state = { - editable: false, - favoriteCount: 0, - loveCount: 0 - }; + this.state = this.initState(); } componentDidUpdate (prevProps) { - let pathname = window.location.pathname.toLowerCase(); - if (pathname[pathname.length - 1] === '/') { - pathname = pathname.substring(0, pathname.length - 1); - } - const path = pathname.split('/'); - const projectId = path[path.length - 1]; if (this.props.sessionStatus !== prevProps.sessionStatus && - this.props.sessionStatus === sessionActions.Status.FETCHED) { + this.props.sessionStatus === sessionActions.Status.FETCHED && + this.state.projectId) { if (this.props.user) { const username = this.props.user.username; const token = this.props.user.token; - this.props.getProjectInfo(projectId, token); - this.props.getRemixes(projectId, token); - this.props.getStudios(projectId, token); - this.props.getFavedStatus(projectId, username, token); - this.props.getLovedStatus(projectId, username, token); + this.props.getProjectInfo(this.state.projectId, token); + this.props.getRemixes(this.state.projectId, token); + this.props.getStudios(this.state.projectId, token); + this.props.getFavedStatus(this.state.projectId, username, token); + this.props.getLovedStatus(this.state.projectId, username, token); } else { - this.props.getProjectInfo(projectId); - this.props.getRemixes(projectId); - this.props.getStudios(projectId); + this.props.getProjectInfo(this.state.projectId); + this.props.getRemixes(this.state.projectId); + this.props.getStudios(this.state.projectId); } } @@ -58,6 +53,33 @@ class Preview extends React.Component { } } } + initState () { + let pathname = window.location.pathname.toLowerCase(); + const params = { + editable: false, + favoriteCount: 0, + inEditor: false, + isFullScreen: false, + loveCount: 0, + projectId: null + }; + if (pathname[pathname.length - 1] === '/') { + pathname = pathname.substring(0, pathname.length - 1); + } + const path = pathname.split('/'); + if (path[path.length - 1] === 'editor' || path[path.length - 1] === 'preview') { + params.inEditor = true; + path.pop(); + } + if (path[path.length - 1] === 'fullscreen') { + params.isFullScreen = true; + path.pop(); + } + if (/^\d+$/.test(path[path.length - 1])) { + params.projectId = path.pop(); + } + return params; + } handleFavoriteToggle () { this.props.setFavedStatus( !this.props.faved, @@ -98,6 +120,10 @@ class Preview extends React.Component { this.setState({editable: true}); } } + handleSeeInside () { + this.setState({inEditor: true}); + history.pushState({}, document.title, `/preview/${this.state.projectId}/editor`); + } handleUpdate (jsonData) { this.props.updateProject( this.props.projectInfo.id, @@ -114,23 +140,35 @@ class Preview extends React.Component { } render () { return ( - + this.state.inEditor ? + : + + + ); } } @@ -268,7 +306,7 @@ const ConnectedPreview = connect( )(Preview); render( - , + , document.getElementById('app'), {preview: previewActions.previewReducer} ); diff --git a/src/views/preview/preview.scss b/src/views/preview/preview.scss index fb608977d..921749f8d 100644 --- a/src/views/preview/preview.scss +++ b/src/views/preview/preview.scss @@ -1,24 +1,24 @@ @import "../../colors"; @import "../../frameless"; -html, -body, -#app, -.gui { - margin: 0; - width: 100%; - height: 100%; -} - /* override view padding for share banner */ #view { padding: 0 0 20px 0; } -.gui * { box-sizing: border-box; } +.gui { + position: absolute; + top: 0; + z-index: 11; + margin: 0; + width: 100%; + height: 100%; +} + +// .gui * { box-sizing: border-box; } .preview { - + .project-title { font-size: 1.75rem; font-weight: 500; @@ -162,15 +162,11 @@ body, align-items: flex-start; } - .placeholder { + .guiPlayer { display: inline-block; width: 480px; } - .placeholder img { - width: 100%; - } - .project-notes { width: 45%; height: 404px; diff --git a/webpack.config.js b/webpack.config.js index 40ad0fd9d..d3e267749 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -142,7 +142,21 @@ module.exports = { new CopyWebpackPlugin([ {from: 'static'}, {from: 'intl', to: 'js'} - ]) + ]), + new CopyWebpackPlugin([{ + from: 'node_modules/scratch-gui/dist/static/blocks-media', + to: 'static/blocks-media' + }]), + new CopyWebpackPlugin([{ + from: 'node_modules/scratch-gui/dist/extension-worker.js' + }]), + new CopyWebpackPlugin([{ + from: 'node_modules/scratch-gui/dist/extension-worker.js.map' + }]), + new CopyWebpackPlugin([{ + from: 'node_modules/scratch-gui/dist/static/assets', + to: 'static/assets' + }]) ]) .concat(process.env.NODE_ENV === 'production' ? [ new webpack.optimize.UglifyJsPlugin({