diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index 6423dbd12fbaac24ac99a49a4ff2d7d7bf0e69dd..572d01bab1ffd3989d2e0a21275779ab9c7112f0 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -18,7 +18,6 @@ import Loader from '../loader/loader.jsx'; import Box from '../box/box.jsx'; import MenuBar from '../menu-bar/menu-bar.jsx'; import PreviewModal from '../../containers/preview-modal.jsx'; -import ImportModal from '../../containers/import-modal.jsx'; import WebGlModal from '../../containers/webgl-modal.jsx'; import layout from '../../lib/layout-constants.js'; @@ -47,7 +46,6 @@ const GUIComponent = props => { blocksTabVisible, children, costumesTabVisible, - importInfoVisible, intl, loading, onExtensionButtonClick, @@ -91,9 +89,6 @@ const GUIComponent = props => { {loading ? ( <Loader /> ) : null} - {importInfoVisible ? ( - <ImportModal /> - ) : null} {isRendererSupported ? null : ( <WebGlModal /> )} @@ -219,7 +214,6 @@ GUIComponent.propTypes = { blocksTabVisible: PropTypes.bool, children: PropTypes.node, costumesTabVisible: PropTypes.bool, - importInfoVisible: PropTypes.bool, intl: intlShape.isRequired, loading: PropTypes.bool, onActivateCostumesTab: PropTypes.func, diff --git a/src/components/import-modal/import-modal.css b/src/components/import-modal/import-modal.css deleted file mode 100644 index 93480429b19e92ee3f8d4fa08883d2a87b9a7530..0000000000000000000000000000000000000000 --- a/src/components/import-modal/import-modal.css +++ /dev/null @@ -1,185 +0,0 @@ -@import "../../css/colors.css"; -@import "../../css/units.css"; -@import "../../css/typography.css"; - -.modal-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 1000; - background-color: $ui-modal-overlay; -} - -.modal-content { - margin: 100px auto; - outline: none; - border: .25rem solid $ui-white-transparent; - padding: 0; - border-radius: $space; - user-select: none; - width: 500px; - color: $text-primary; - overflow: hidden; -} - -/* - TODO figure out how to remove filter altogether - since it is null... - Modal header has 3 items: - |x title filter| - - Use the same width for both side item containers, - so that title remains centered -*/ -$sides: 20rem; - -.header { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - justify-content: flex-start; - height: $library-header-height; - - box-sizing: border-box; - width: 100%; - background-color: $pen-primary; -} - -.header-item { - display: flex; - align-items: center; - padding: 1rem; - text-decoration: none; - color: white; - user-select: none; -} - -.header-item-filter { - display: flex; - flex-basis: $sides; - justify-content: flex-end; -} - -.header-item-title { - flex-grow: 1; - flex-shrink: 0; - justify-content: center; - user-select: none; - letter-spacing: 0.4px; - cursor: default; -} - -.header-item-title h2 { - font-size: 1.25rem; -} - -.header-item-close { - display: flex; - flex-basis: $sides; - justify-content: flex-start; -} - -.body { - background: $ui-white; - padding: 1.5rem 2.25rem; - text-align: center; -} - -.input-row { - margin: 1.5rem 0; - font-weight: bolder; - text-align: right; - display: flex; - justify-content: center; - border: 1px solid; - border-radius: 0.25rem; - overflow: hidden; -} - -.ok-input-container { - border-color: $motion-primary; - box-shadow: 0 0 0 0.2rem $motion-transparent; -} - -.bad-input-container { - border-color: $data-primary; - box-shadow: 0 0 0 0.2rem hsla(30, 100%, 55%, 0.15); -} - -.input-row input { - width: 100%; - padding: 0 1rem; - height: 3rem; - color: $text-primary; - font-size: .875rem; - outline: none; - border: none; -} - -.input-row input::placeholder { - font-style: italic; - color: $text-primary-transparent; -} - -.input-row button { - padding: 0.5rem 2rem; - font-weight: bold; - font-size: .875rem; - cursor: pointer; - border: 0px solid $pen-primary; - outline: none; -} - -.input-row button.ok-button { - background: $pen-primary; - color: white; -} - -.error-row { - margin: 1.5rem 0; - text-align: center; - display: flex; - justify-content: center; - background: hsla(30, 100%, 55%, 0.25); - color: $data-primary; - border: 1px solid $data-primary; - border-radius: 0.25rem; -} - -.error-row p { - font-size: 0.875rem; - font-weight: bold; -} - -/* Confirmation buttons at the bottom of the modal */ -.button-row { - margin: 1.5rem 0; - font-weight: bolder; - text-align: right; - display: flex; - justify-content: center; -} - -.button-row button { - border: 1px solid $motion-primary; - border-radius: 0.25rem; - padding: 0.5rem 1.5rem; - background: white; - font-weight: bold; - font-size: .875rem; - cursor: pointer; - color: $motion-primary; -} - -.faq-link-text { - margin: 2rem 0 .5rem 0; - font-size: .875rem; - color: $text-primary; -} - -.faq-link { - color: $motion-primary; - text-decoration: none; -} diff --git a/src/components/import-modal/import-modal.jsx b/src/components/import-modal/import-modal.jsx deleted file mode 100644 index ad42929e7d6c24afced4c2febf2bda976ea27f2b..0000000000000000000000000000000000000000 --- a/src/components/import-modal/import-modal.jsx +++ /dev/null @@ -1,155 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import ReactModal from 'react-modal'; -import Box from '../box/box.jsx'; -import {defineMessages, injectIntl, intlShape, FormattedMessage} from 'react-intl'; -import classNames from 'classnames'; - -import CloseButton from '../close-button/close-button.jsx'; - -import styles from './import-modal.css'; - -const messages = defineMessages({ - title: { - id: 'gui.importInfo.title', - defaultMessage: 'View a Scratch 2.0 Project', - description: 'Scratch 2.0 import modal label - for accessibility' - }, - formDescription: { - defaultMessage: - 'Enter a link to one of your shared Scratch projects. Changes made in this 3.0 Preview will not be saved.', - description: 'Import project message', - id: 'gui.importInfo.message' - }, - invalidFormatError: { - id: 'gui.importInfo.invalidFormatError', - defaultMessage: 'Uh oh, that project link or id doesn\'t look quite right.', - description: 'Invalid project link or id message' - } -}); - -const ImportModal = ({intl, ...props}) => ( - <ReactModal - isOpen - className={styles.modalContent} - contentLabel={intl.formatMessage({...messages.title})} - overlayClassName={styles.modalOverlay} - onRequestClose={props.onCancel} - > - <Box> - <div className={styles.header}> - <div - className={classNames( - styles.headerItem, - styles.headerItemClose - )} - > - <CloseButton - buttonType="back" - size={CloseButton.SIZE_LARGE} - onClick={props.onGoBack} - /> - </div> - <div - className={classNames( - styles.headerItem, - styles.headerItemTitle - )} - > - <h2> - {intl.formatMessage({...messages.title})} - </h2> - </div> - <div className={classNames(styles.headerItem, styles.headerItemFilter)}> - {null} - </div> - </div> - </Box> - - <Box className={styles.body}> - <p> - {intl.formatMessage({...messages.formDescription})} - </p> - <Box - className={classNames(styles.inputRow, - (props.hasValidationError ? styles.badInputContainer : styles.okInputContainer)) - } - > - <input - autoFocus - placeholder={props.placeholder} - value={props.inputValue} - onChange={props.onChange} - onKeyPress={props.onKeyPress} - /> - <button - className={styles.okButton} - title="viewproject" - onClick={props.onViewProject} - > - <FormattedMessage - defaultMessage="View" - description="Label for button to load a scratch 2.0 project" - id="gui.importModal.viewproject" - /> - </button> - </Box> - {props.hasValidationError ? - <Box className={styles.errorRow}> - <p> - <FormattedMessage - {...messages[`${props.errorMessage}`]} - /> - </p> - </Box> : null - } - <Box className={styles.buttonRow}> - <button - onClick={props.onGoBack} - > - <FormattedMessage - defaultMessage="Go Back" - description="Label for button to back out of importing a project" - id="gui.importInfo.goback" - /> - </button> - </Box> - <Box className={styles.faqLinkText}> - <FormattedMessage - defaultMessage="To learn more, go to the {previewFaqLink}." - description="Invitation to try 3.0 preview" - id="gui.importInfo.previewfaq" - values={{ - previewFaqLink: ( - <a - className={styles.faqLink} - href="//scratch.mit.edu/preview-faq" - > - <FormattedMessage - defaultMessage="Preview FAQ" - description="link to Scratch 3.0 preview FAQ page" - id="gui.importInfo.previewfaqlink" - /> - </a> - ) - }} - /> - </Box> - </Box> - </ReactModal> -); - -ImportModal.propTypes = { - errorMessage: PropTypes.string.isRequired, - hasValidationError: PropTypes.bool.isRequired, - inputValue: PropTypes.string.isRequired, - intl: intlShape.isRequired, - onCancel: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onGoBack: PropTypes.func.isRequired, - onKeyPress: PropTypes.func.isRequired, - onViewProject: PropTypes.func.isRequired, - placeholder: PropTypes.string -}; - -export default injectIntl(ImportModal); diff --git a/src/components/preview-modal/preview-modal.css b/src/components/preview-modal/preview-modal.css index 837ed92cfef69fd1ff77f9567483455f7c02d074..a746c9178290202bd1a6d9165322f339d3dfed65 100644 --- a/src/components/preview-modal/preview-modal.css +++ b/src/components/preview-modal/preview-modal.css @@ -39,6 +39,12 @@ text-align: center; } +.disclaimer { + margin-top: 2.0rem; + border-top: 1px solid $text-primary; + padding-top: 1.0rem; +} + /* Confirmation buttons at the bottom of the modal */ .button-row { margin: 1.5rem 0; @@ -67,12 +73,6 @@ color: $motion-primary; } -.button-row button.view-project-button { - background: $pen-primary; - border-color: $pen-primary; - color: white; -} - .button-row button + button { margin-left: 0.5rem; } diff --git a/src/components/preview-modal/preview-modal.jsx b/src/components/preview-modal/preview-modal.jsx index 5772b518539a7541f30859a3aef6540eef030878..9e86e5434b4f9cdd24a1e4ad97481043c0a8845a 100644 --- a/src/components/preview-modal/preview-modal.jsx +++ b/src/components/preview-modal/preview-modal.jsx @@ -35,12 +35,45 @@ const PreviewModal = ({intl, ...props}) => ( </h2> <p> <FormattedMessage - defaultMessage="We're working on the next generation of Scratch. We're excited for you to try it!" + defaultMessage="We're excited for you to try the next generation of Scratch! + To learn more, go to the {previewFaqLink}." description="Invitation to try 3.0 preview" - id="gui.previewInfo.invitation" + id="gui.previewInfo.previewfaq" + values={{ + previewFaqLink: ( + <a + className={styles.faqLink} + href="//scratch.mit.edu/preview-faq" + > + <FormattedMessage + defaultMessage="Preview FAQ" + description="link to Scratch 3.0 preview FAQ page" + id="gui.previewInfo.previewfaqlink" + /> + </a> + ) + }} /> </p> + <Box className={styles.disclaimer}> + <p> + <strong> + <FormattedMessage + defaultMessage="Changes to projects will not be saved." + description="Disclaimer for 3.0 preview" + id="gui.previewInfo.disclaimer" + /> + <br /> + <FormattedMessage + defaultMessage="This feature is coming soon!" + description="Notice that a feature is in progress" + id="gui.previewInfo.comingsoon" + /> + </strong> + </p> + </Box> + <Box className={styles.buttonRow}> <button className={styles.noButton} @@ -71,38 +104,6 @@ const PreviewModal = ({intl, ...props}) => ( }} /> </button> - <button - className={styles.viewProjectButton} - title="viewproject" - onClick={props.onViewProject} - > - <FormattedMessage - defaultMessage="View 2.0 Project" - description="Label for button to import a 2.0 project" - id="gui.previewModal.viewproject" - /> - </button> - </Box> - <Box className={styles.faqLinkText}> - <FormattedMessage - defaultMessage="To learn more, go to the {previewFaqLink}." - description="Invitation to try 3.0 preview" - id="gui.previewInfo.previewfaq" - values={{ - previewFaqLink: ( - <a - className={styles.faqLink} - href="//scratch.mit.edu/preview-faq" - > - <FormattedMessage - defaultMessage="Preview FAQ" - description="link to Scratch 3.0 preview FAQ page" - id="gui.previewInfo.previewfaqlink" - /> - </a> - ) - }} - /> </Box> </Box> </ReactModal> @@ -111,8 +112,7 @@ const PreviewModal = ({intl, ...props}) => ( PreviewModal.propTypes = { intl: intlShape.isRequired, onCancel: PropTypes.func.isRequired, - onTryIt: PropTypes.func.isRequired, - onViewProject: PropTypes.func.isRequired + onTryIt: PropTypes.func.isRequired }; export default injectIntl(PreviewModal); diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx index 73e5f337518da9d50a09d69c11aa3e7603fee475..cd2a5a95f76648e57b592e84f10a6e7ba16ca560 100644 --- a/src/containers/gui.jsx +++ b/src/containers/gui.jsx @@ -86,7 +86,6 @@ class GUI extends React.Component { GUI.propTypes = { ...GUIComponent.propTypes, fetchingProject: PropTypes.bool, - importInfoVisible: PropTypes.bool, loadingStateVisible: PropTypes.bool, previewInfoVisible: PropTypes.bool, projectData: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), @@ -99,7 +98,6 @@ const mapStateToProps = state => ({ activeTabIndex: state.editorTab.activeTabIndex, blocksTabVisible: state.editorTab.activeTabIndex === BLOCKS_TAB_INDEX, costumesTabVisible: state.editorTab.activeTabIndex === COSTUMES_TAB_INDEX, - importInfoVisible: state.modals.importInfo, loadingStateVisible: state.modals.loadingProject, previewInfoVisible: state.modals.previewInfo, soundsTabVisible: state.editorTab.activeTabIndex === SOUNDS_TAB_INDEX diff --git a/src/containers/import-modal.jsx b/src/containers/import-modal.jsx deleted file mode 100644 index 0731098f1563c2fda54258c807babc0872ee4638..0000000000000000000000000000000000000000 --- a/src/containers/import-modal.jsx +++ /dev/null @@ -1,111 +0,0 @@ -import bindAll from 'lodash.bindall'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {connect} from 'react-redux'; - -import ImportModalComponent from '../components/import-modal/import-modal.jsx'; - -import { - closeImportInfo, - openPreviewInfo -} from '../reducers/modals'; - -class ImportModal extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleViewProject', - 'handleCancel', - 'handleChange', - 'handleGoBack', - 'handleKeyPress' - ]); - - this.state = { - inputValue: '', - hasValidationError: false, - errorMessage: '' - }; - } - handleKeyPress (event) { - if (event.key === 'Enter') this.handleViewProject(); - } - handleViewProject () { - const inputValue = this.state.inputValue; - const projectId = this.validate(inputValue); - - if (projectId) { - const projectLink = document.createElement('a'); - document.body.appendChild(projectLink); - projectLink.href = `#${projectId}`; - projectLink.click(); - document.body.removeChild(projectLink); - this.props.onViewProject(); - } else { - this.setState({ - hasValidationError: true, - errorMessage: `invalidFormatError`}); - } - } - handleChange (e) { - this.setState({inputValue: e.target.value, hasValidationError: false}); - } - validate (input) { - const urlMatches = input.match(/^(?:https?:\/\/)?scratch\.mit\.edu\/projects\/(\d+)/); - if (urlMatches && urlMatches.length > 0) { - return urlMatches[1]; - } - const projectIdMatches = input.match(/^#?(\d+)$/); - if (projectIdMatches && projectIdMatches.length > 0) { - return projectIdMatches[1]; - } - return null; - } - handleCancel () { - this.props.onCancel(); - } - handleGoBack () { - this.props.onBack(); - } - render () { - return ( - <ImportModalComponent - errorMessage={this.state.errorMessage} - hasValidationError={this.state.hasValidationError} - inputValue={this.state.inputValue} - placeholder="scratch.mit.edu/projects/123456789" - onCancel={this.handleCancel} - onChange={this.handleChange} - onGoBack={this.handleGoBack} - onKeyPress={this.handleKeyPress} - onViewProject={this.handleViewProject} - /> - ); - } -} - -ImportModal.propTypes = { - onBack: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired, - onViewProject: PropTypes.func -}; - -const mapStateToProps = () => ({}); - -const mapDispatchToProps = dispatch => ({ - onBack: () => { - dispatch(closeImportInfo()); - dispatch(openPreviewInfo()); - }, - onCancel: () => { - dispatch(closeImportInfo()); - }, - onViewProject: () => { - dispatch(closeImportInfo()); - } -}); - -export default connect( - mapStateToProps, - mapDispatchToProps -)(ImportModal); diff --git a/src/containers/preview-modal.jsx b/src/containers/preview-modal.jsx index 3fa6c8f03f97eea04d8e1ed3b69c50ca2e070b0a..70fb3290b18feac202a67336fec48f4b5b1a1682 100644 --- a/src/containers/preview-modal.jsx +++ b/src/containers/preview-modal.jsx @@ -8,8 +8,7 @@ import PreviewModalComponent from '../components/preview-modal/preview-modal.jsx import BrowserModalComponent from '../components/browser-modal/browser-modal.jsx'; import { - closePreviewInfo, - openImportInfo + closePreviewInfo } from '../reducers/modals'; class PreviewModal extends React.Component { @@ -17,8 +16,7 @@ class PreviewModal extends React.Component { super(props); bindAll(this, [ 'handleTryIt', - 'handleCancel', - 'handleViewProject' + 'handleCancel' ]); this.state = { @@ -32,9 +30,6 @@ class PreviewModal extends React.Component { handleCancel () { window.location.replace('https://scratch.mit.edu'); } - handleViewProject () { - this.props.onViewProject(); - } supportedBrowser () { return !['IE', 'Opera', 'Opera Mini', 'Silk', 'Vivaldi'].includes(platform.name); } @@ -44,7 +39,6 @@ class PreviewModal extends React.Component { previewing={this.state.previewing} onCancel={this.handleCancel} onTryIt={this.handleTryIt} - onViewProject={this.handleViewProject} /> : <BrowserModalComponent onBack={this.handleCancel} @@ -54,8 +48,7 @@ class PreviewModal extends React.Component { } PreviewModal.propTypes = { - onTryIt: PropTypes.func, - onViewProject: PropTypes.func + onTryIt: PropTypes.func }; const mapStateToProps = () => ({}); @@ -63,10 +56,6 @@ const mapStateToProps = () => ({}); const mapDispatchToProps = dispatch => ({ onTryIt: () => { dispatch(closePreviewInfo()); - }, - onViewProject: () => { - dispatch(closePreviewInfo()); - dispatch(openImportInfo()); } }); diff --git a/src/reducers/modals.js b/src/reducers/modals.js index 2bce0635cf7542f9dfc6df3d8c129128805e1ef7..ce2e91b3365be8b25a136a636ebcb4996de37cd2 100644 --- a/src/reducers/modals.js +++ b/src/reducers/modals.js @@ -6,7 +6,6 @@ const CLOSE_MODAL = 'scratch-gui/modals/CLOSE_MODAL'; const MODAL_BACKDROP_LIBRARY = 'backdropLibrary'; const MODAL_COSTUME_LIBRARY = 'costumeLibrary'; const MODAL_EXTENSION_LIBRARY = 'extensionLibrary'; -const MODAL_IMPORT_INFO = 'importInfo'; const MODAL_LOADING_PROJECT = 'loadingProject'; const MODAL_PREVIEW_INFO = 'previewInfo'; const MODAL_SOUND_LIBRARY = 'soundLibrary'; @@ -18,7 +17,6 @@ const initialState = { [MODAL_BACKDROP_LIBRARY]: false, [MODAL_COSTUME_LIBRARY]: false, [MODAL_EXTENSION_LIBRARY]: false, - [MODAL_IMPORT_INFO]: false, [MODAL_LOADING_PROJECT]: false, [MODAL_PREVIEW_INFO]: true, [MODAL_SOUND_LIBRARY]: false, @@ -65,10 +63,6 @@ const openExtensionLibrary = function () { analytics.pageview('/libraries/extensions'); return openModal(MODAL_EXTENSION_LIBRARY); }; -const openImportInfo = function () { - analytics.pageview('modals/import'); - return openModal(MODAL_IMPORT_INFO); -}; const openLoadingProject = function () { analytics.pageview('modals/loading'); return openModal(MODAL_LOADING_PROJECT); @@ -98,9 +92,6 @@ const closeCostumeLibrary = function () { const closeExtensionLibrary = function () { return closeModal(MODAL_EXTENSION_LIBRARY); }; -const closeImportInfo = function () { - return closeModal(MODAL_IMPORT_INFO); -}; const closeLoadingProject = function () { return closeModal(MODAL_LOADING_PROJECT); }; @@ -121,7 +112,6 @@ export { openBackdropLibrary, openCostumeLibrary, openExtensionLibrary, - openImportInfo, openLoadingProject, openPreviewInfo, openSoundLibrary, @@ -130,7 +120,6 @@ export { closeBackdropLibrary, closeCostumeLibrary, closeExtensionLibrary, - closeImportInfo, closeLoadingProject, closePreviewInfo, closeSpriteLibrary, diff --git a/test/integration/project-loading.test.js b/test/integration/project-loading.test.js index cb0477ec9317a9fbb2fc0ca91c3e564b1b525ad2..cb36f20e5f7352338b99c58281d0daadd00cc65e 100644 --- a/test/integration/project-loading.test.js +++ b/test/integration/project-loading.test.js @@ -4,7 +4,6 @@ import SeleniumHelper from '../helpers/selenium-helper'; const { clickText, clickXpath, - findByXpath, getDriver, getLogs, loadUri @@ -31,40 +30,6 @@ describe('Loading scratch gui', () => { }); describe('Loading projects by ID', () => { - - test('Load 2.0 project using import modal', async () => { - await loadUri(uri); - await clickText('View 2.0 Project'); - const el = await findByXpath("//input[@placeholder='scratch.mit.edu/projects/123456789']"); - const projectId = '96708228'; - await el.sendKeys(`scratch.mit.edu/projects/${projectId}`); - await clickXpath('//button[@title="viewproject"]'); - await new Promise(resolve => setTimeout(resolve, 2000)); - await clickXpath('//img[@title="Go"]'); - await new Promise(resolve => setTimeout(resolve, 2000)); - await clickXpath('//img[@title="Stop"]'); - const logs = await getLogs(); - await expect(logs).toEqual([]); - }); - - test('Invalid url when loading project through modal lets you try again', async () => { - await loadUri(uri); - await clickText('View 2.0 Project'); - let el = await findByXpath("//input[@placeholder='scratch.mit.edu/projects/123456789']"); - await el.sendKeys('thisisnotaurl'); - await clickXpath('//button[@title="viewproject"]'); - el = await findByXpath("//input[@placeholder='scratch.mit.edu/projects/123456789']"); - await el.clear(); - await el.sendKeys('scratch.mit.edu/projects/96708228'); - await clickXpath('//button[@title="viewproject"]'); - await new Promise(resolve => setTimeout(resolve, 2000)); - await clickXpath('//img[@title="Go"]'); - await new Promise(resolve => setTimeout(resolve, 2000)); - await clickXpath('//img[@title="Stop"]'); - const logs = await getLogs(); - await expect(logs).toEqual([]); - }); - test('Load a project by ID directly through url', async () => { await driver.quit(); // Reset driver to test hitting # url directly driver = getDriver();