Merge branch 'develop' into feature/mobile-login
This commit is contained in:
		
						commit
						f844023aed
					
				
					 11 changed files with 124 additions and 58 deletions
				
			
		|  | @ -3,3 +3,21 @@ import '@babel/polyfill'; | |||
| // See: https://github.com/testing-library/jest-dom
 | ||||
| // eslint-disable-next-line import/no-extraneous-dependencies
 | ||||
| import '@testing-library/jest-dom'; | ||||
| 
 | ||||
| import lodash from 'lodash'; | ||||
| 
 | ||||
| // For testing, we use en-US and provide a mock implementation
 | ||||
| // of t() that finds the correct translation
 | ||||
| import translations from '../translations/locales/en-US/translations.json'; | ||||
| 
 | ||||
| // This function name needs to be prefixed with "mock" so that Jest doesn't
 | ||||
| // complain that it's out-of-scope in the mock below
 | ||||
| const mockTranslate = key => lodash.get(translations, key); | ||||
| 
 | ||||
| jest.mock('react-i18next', () => ({ | ||||
|   // this mock makes sure any components using the translate HoC receive the t function as a prop
 | ||||
|   withTranslation: () => (Component) => { | ||||
|     Component.defaultProps = { ...Component.defaultProps, t: mockTranslate }; | ||||
|     return Component; | ||||
|   }, | ||||
| })); | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ import Loader from '../../App/components/loader'; | |||
| import QuickAddList from './QuickAddList'; | ||||
| 
 | ||||
| const projectInCollection = (project, collection) => | ||||
|   collection.items.find(item => item.project.id === project.id) != null; | ||||
|   collection.items.find(item => item.projectId === project.id) != null; | ||||
| 
 | ||||
| class CollectionList extends React.Component { | ||||
|   constructor(props) { | ||||
|  | @ -81,12 +81,14 @@ class CollectionList extends React.Component { | |||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className="quick-add-wrapper"> | ||||
|         <Helmet> | ||||
|           <title>{this.getTitle()}</title> | ||||
|         </Helmet> | ||||
|       <div className="collection-add-sketch"> | ||||
|         <div className="quick-add-wrapper"> | ||||
|           <Helmet> | ||||
|             <title>{this.getTitle()}</title> | ||||
|           </Helmet> | ||||
| 
 | ||||
|         {content} | ||||
|           {content} | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  |  | |||
|  | @ -72,11 +72,13 @@ class SketchList extends React.Component { | |||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className="quick-add-wrapper"> | ||||
|         <Helmet> | ||||
|           <title>{this.getSketchesTitle()}</title> | ||||
|         </Helmet> | ||||
|         {content} | ||||
|       <div className="collection-add-sketch"> | ||||
|         <div className="quick-add-wrapper"> | ||||
|           <Helmet> | ||||
|             <title>{this.getSketchesTitle()}</title> | ||||
|           </Helmet> | ||||
|           {content} | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  |  | |||
|  | @ -170,12 +170,10 @@ class CollectionList extends React.Component { | |||
|               closeOverlay={this.hideAddSketches} | ||||
|               isFixedHeight | ||||
|             > | ||||
|               <div className="collection-add-sketch"> | ||||
|                 <AddToCollectionSketchList | ||||
|                   username={this.props.username} | ||||
|                   collection={find(this.props.collections, { id: this.state.addingSketchesToCollectionId })} | ||||
|                 /> | ||||
|               </div> | ||||
|               <AddToCollectionSketchList | ||||
|                 username={this.props.username} | ||||
|                 collection={find(this.props.collections, { id: this.state.addingSketchesToCollectionId })} | ||||
|               /> | ||||
|             </Overlay> | ||||
|           ) | ||||
|         } | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| import React, { useRef } from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { withTranslation } from 'react-i18next'; | ||||
| 
 | ||||
| import { bindActionCreators } from 'redux'; | ||||
| 
 | ||||
|  | @ -72,7 +74,7 @@ const getConsoleFeedStyle = (theme, times, fontSize) => { | |||
|   } | ||||
| }; | ||||
| 
 | ||||
| const Console = () => { | ||||
| const Console = ({ t }) => { | ||||
|   const consoleEvents = useSelector(state => state.console); | ||||
|   const isExpanded = useSelector(state => state.ide.consoleIsExpanded); | ||||
|   const { theme, fontSize } = useSelector(state => state.preferences); | ||||
|  | @ -98,19 +100,19 @@ const Console = () => { | |||
|   return ( | ||||
|     <section className={consoleClass} > | ||||
|       <header className="preview-console__header"> | ||||
|         <h2 className="preview-console__header-title">Console</h2> | ||||
|         <h2 className="preview-console__header-title">{t('Console.Title')}</h2> | ||||
|         <div className="preview-console__header-buttons"> | ||||
|           <button className="preview-console__clear" onClick={clearConsole} aria-label="Clear console"> | ||||
|             Clear | ||||
|           <button className="preview-console__clear" onClick={clearConsole} aria-label={t('Console.ClearARIA')}> | ||||
|             {t('Console.Clear')} | ||||
|           </button> | ||||
|           <button | ||||
|             className="preview-console__collapse" | ||||
|             onClick={collapseConsole} | ||||
|             aria-label="Close console" | ||||
|             aria-label={t('Console.CloseARIA')} | ||||
|           > | ||||
|             <DownArrowIcon focusable="false" aria-hidden="true" /> | ||||
|           </button> | ||||
|           <button className="preview-console__expand" onClick={expandConsole} aria-label="Open console" > | ||||
|           <button className="preview-console__expand" onClick={expandConsole} aria-label={t('Console.OpenARIA')} > | ||||
|             <UpArrowIcon focusable="false" aria-hidden="true" /> | ||||
|           </button> | ||||
|         </div> | ||||
|  | @ -140,5 +142,9 @@ const Console = () => { | |||
|   ); | ||||
| }; | ||||
| 
 | ||||
| Console.propTypes = { | ||||
|   t: PropTypes.func.isRequired, | ||||
| }; | ||||
| 
 | ||||
| export default Console; | ||||
| 
 | ||||
| export default withTranslation()(Console); | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ import React from 'react'; | |||
| import { bindActionCreators } from 'redux'; | ||||
| import { connect } from 'react-redux'; | ||||
| import classNames from 'classnames'; | ||||
| import { withTranslation } from 'react-i18next'; | ||||
| 
 | ||||
| import * as IDEActions from '../actions/ide'; | ||||
| import * as FileActions from '../actions/files'; | ||||
| import DownArrowIcon from '../../../images/down-filled-triangle.svg'; | ||||
|  | @ -152,7 +154,9 @@ export class FileNode extends React.Component { | |||
|   } | ||||
| 
 | ||||
|   handleClickDelete = () => { | ||||
|     if (window.confirm(`Are you sure you want to delete ${this.props.name}?`)) { | ||||
|     const prompt = this.props.t('Common.DeleteConfirmation', { name: this.props.name }); | ||||
| 
 | ||||
|     if (window.confirm(prompt)) { | ||||
|       this.setState({ isDeleting: true }); | ||||
|       this.props.resetSelectedFile(this.props.id); | ||||
|       setTimeout(() => this.props.deleteFile(this.props.id, this.props.parentId), 100); | ||||
|  | @ -237,6 +241,8 @@ export class FileNode extends React.Component { | |||
|     const isFolder = this.props.fileType === 'folder'; | ||||
|     const isRoot = this.props.name === 'root'; | ||||
| 
 | ||||
|     const { t } = this.props; | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={itemClass} > | ||||
|         { !isRoot && | ||||
|  | @ -252,14 +258,14 @@ export class FileNode extends React.Component { | |||
|                 <button | ||||
|                   className="sidebar__file-item-closed" | ||||
|                   onClick={this.showFolderChildren} | ||||
|                   aria-label="Open folder contents" | ||||
|                   aria-label={t('FileNode.OpenFolderARIA')} | ||||
|                 > | ||||
|                   <FolderRightIcon className="folder-right" focusable="false" aria-hidden="true" /> | ||||
|                 </button> | ||||
|                 <button | ||||
|                   className="sidebar__file-item-open" | ||||
|                   onClick={this.hideFolderChildren} | ||||
|                   aria-label="Close file contents" | ||||
|                   aria-label={t('FileNode.CloseFolderARIA')} | ||||
|                 > | ||||
|                   <FolderDownIcon className="folder-down" focusable="false" aria-hidden="true" /> | ||||
|                 </button> | ||||
|  | @ -286,7 +292,7 @@ export class FileNode extends React.Component { | |||
|             /> | ||||
|             <button | ||||
|               className="sidebar__file-item-show-options" | ||||
|               aria-label="Toggle open/close file options" | ||||
|               aria-label={t('FileNode.ToggleFileOptionsARIA')} | ||||
|               ref={(element) => { this[`fileOptions-${this.props.id}`] = element; }} | ||||
|               tabIndex="0" | ||||
|               onClick={this.toggleFileOptions} | ||||
|  | @ -301,35 +307,35 @@ export class FileNode extends React.Component { | |||
|                   <React.Fragment> | ||||
|                     <li> | ||||
|                       <button | ||||
|                         aria-label="add folder" | ||||
|                         aria-label={t('FileNode.AddFolderARIA')} | ||||
|                         onClick={this.handleClickAddFolder} | ||||
|                         onBlur={this.onBlurComponent} | ||||
|                         onFocus={this.onFocusComponent} | ||||
|                         className="sidebar__file-item-option" | ||||
|                       > | ||||
|                         Create folder | ||||
|                         {t('FileNode.AddFolder')} | ||||
|                       </button> | ||||
|                     </li> | ||||
|                     <li> | ||||
|                       <button | ||||
|                         aria-label="add file" | ||||
|                         aria-label={t('FileNode.AddFileARIA')} | ||||
|                         onClick={this.handleClickAddFile} | ||||
|                         onBlur={this.onBlurComponent} | ||||
|                         onFocus={this.onFocusComponent} | ||||
|                         className="sidebar__file-item-option" | ||||
|                       > | ||||
|                         Create file | ||||
|                         {t('FileNode.AddFile')} | ||||
|                       </button> | ||||
|                     </li> | ||||
|                     { this.props.authenticated && | ||||
|                       <li> | ||||
|                         <button | ||||
|                           aria-label="upload file" | ||||
|                           aria-label={t('FileNode.UploadFileARIA')} | ||||
|                           onClick={this.handleClickUploadFile} | ||||
|                           onBlur={this.onBlurComponent} | ||||
|                           onFocus={this.onFocusComponent} | ||||
|                         > | ||||
|                           Upload file | ||||
|                           {t('FileNode.UploadFile')} | ||||
|                         </button> | ||||
|                       </li> | ||||
|                     } | ||||
|  | @ -342,7 +348,7 @@ export class FileNode extends React.Component { | |||
|                     onFocus={this.onFocusComponent} | ||||
|                     className="sidebar__file-item-option" | ||||
|                   > | ||||
|                     Rename | ||||
|                     {t('FileNode.Rename')} | ||||
|                   </button> | ||||
|                 </li> | ||||
|                 <li> | ||||
|  | @ -352,7 +358,7 @@ export class FileNode extends React.Component { | |||
|                     onFocus={this.onFocusComponent} | ||||
|                     className="sidebar__file-item-option" | ||||
|                   > | ||||
|                     Delete | ||||
|                     {t('FileNode.Delete')} | ||||
|                   </button> | ||||
|                 </li> | ||||
|               </ul> | ||||
|  | @ -388,6 +394,7 @@ FileNode.propTypes = { | |||
|   canEdit: PropTypes.bool.isRequired, | ||||
|   openUploadFileModal: PropTypes.func.isRequired, | ||||
|   authenticated: PropTypes.bool.isRequired, | ||||
|   t: PropTypes.func.isRequired, | ||||
|   onClickFile: PropTypes.func | ||||
| }; | ||||
| 
 | ||||
|  | @ -408,5 +415,8 @@ function mapDispatchToProps(dispatch) { | |||
|   return bindActionCreators(Object.assign(FileActions, IDEActions), dispatch); | ||||
| } | ||||
| 
 | ||||
| const ConnectedFileNode = connect(mapStateToProps, mapDispatchToProps)(FileNode); | ||||
| const TranslatedFileNode = withTranslation()(FileNode); | ||||
| 
 | ||||
| const ConnectedFileNode = connect(mapStateToProps, mapDispatchToProps)(TranslatedFileNode); | ||||
| 
 | ||||
| export default ConnectedFileNode; | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| import PropTypes from 'prop-types'; | ||||
| import React from 'react'; | ||||
| import classNames from 'classnames'; | ||||
| import { withTranslation } from 'react-i18next'; | ||||
| 
 | ||||
| import ConnectedFileNode from './FileNode'; | ||||
| 
 | ||||
| import DownArrowIcon from '../../../images/down-filled-triangle.svg'; | ||||
|  | @ -71,11 +73,11 @@ class Sidebar extends React.Component { | |||
|       <section className={sidebarClass}> | ||||
|         <header className="sidebar__header" onContextMenu={this.toggleProjectOptions}> | ||||
|           <h3 className="sidebar__title"> | ||||
|             <span>Sketch Files</span> | ||||
|             <span>{this.props.t('Sidebar.Title')}</span> | ||||
|           </h3> | ||||
|           <div className="sidebar__icons"> | ||||
|             <button | ||||
|               aria-label="Toggle open/close sketch file options" | ||||
|               aria-label={this.props.t('Sidebar.ToggleARIA')} | ||||
|               className="sidebar__add" | ||||
|               tabIndex="0" | ||||
|               ref={(element) => { this.sidebarOptions = element; }} | ||||
|  | @ -88,7 +90,7 @@ class Sidebar extends React.Component { | |||
|             <ul className="sidebar__project-options"> | ||||
|               <li> | ||||
|                 <button | ||||
|                   aria-label="add folder" | ||||
|                   aria-label={this.props.t('Sidebar.AddFolderARIA')} | ||||
|                   onClick={() => { | ||||
|                     this.props.newFolder(rootFile.id); | ||||
|                     setTimeout(this.props.closeProjectOptions, 0); | ||||
|  | @ -96,12 +98,12 @@ class Sidebar extends React.Component { | |||
|                   onBlur={this.onBlurComponent} | ||||
|                   onFocus={this.onFocusComponent} | ||||
|                 > | ||||
|                   Create folder | ||||
|                   {this.props.t('Sidebar.AddFolder')} | ||||
|                 </button> | ||||
|               </li> | ||||
|               <li> | ||||
|                 <button | ||||
|                   aria-label="add file" | ||||
|                   aria-label={this.props.t('Sidebar.AddFileARIA')} | ||||
|                   onClick={() => { | ||||
|                     this.props.newFile(rootFile.id); | ||||
|                     setTimeout(this.props.closeProjectOptions, 0); | ||||
|  | @ -109,14 +111,14 @@ class Sidebar extends React.Component { | |||
|                   onBlur={this.onBlurComponent} | ||||
|                   onFocus={this.onFocusComponent} | ||||
|                 > | ||||
|                   Create file | ||||
|                   {this.props.t('Sidebar.AddFile')} | ||||
|                 </button> | ||||
|               </li> | ||||
|               { | ||||
|                 this.props.user.authenticated && | ||||
|                 <li> | ||||
|                   <button | ||||
|                     aria-label="upload file" | ||||
|                     aria-label={this.props.t('Sidebar.UploadFileARIA')} | ||||
|                     onClick={() => { | ||||
|                       this.props.openUploadFileModal(rootFile.id); | ||||
|                       setTimeout(this.props.closeProjectOptions, 0); | ||||
|  | @ -124,7 +126,7 @@ class Sidebar extends React.Component { | |||
|                     onBlur={this.onBlurComponent} | ||||
|                     onFocus={this.onFocusComponent} | ||||
|                   > | ||||
|                     Upload file | ||||
|                     {this.props.t('Sidebar.UploadFile')} | ||||
|                   </button> | ||||
|                 </li> | ||||
|               } | ||||
|  | @ -159,11 +161,12 @@ Sidebar.propTypes = { | |||
|   user: PropTypes.shape({ | ||||
|     id: PropTypes.string, | ||||
|     authenticated: PropTypes.bool.isRequired | ||||
|   }).isRequired | ||||
|   }).isRequired, | ||||
|   t: PropTypes.func.isRequired, | ||||
| }; | ||||
| 
 | ||||
| Sidebar.defaultProps = { | ||||
|   owner: undefined | ||||
| }; | ||||
| 
 | ||||
| export default Sidebar; | ||||
| export default withTranslation()(Sidebar); | ||||
|  |  | |||
|  | @ -398,9 +398,10 @@ class Collection extends React.Component { | |||
|                     closeOverlay={this.hideAddSketches} | ||||
|                     isFixedHeight | ||||
|                   > | ||||
|                     <div className="collection-add-sketch"> | ||||
|                       <AddToCollectionSketchList username={this.props.username} collection={this.props.collection} /> | ||||
|                     </div> | ||||
|                     <AddToCollectionSketchList | ||||
|                       username={this.props.username} | ||||
|                       collection={this.props.collection} | ||||
|                     /> | ||||
|                   </Overlay> | ||||
|                 ) | ||||
|               } | ||||
|  |  | |||
|  | @ -88,6 +88,7 @@ $themes: ( | |||
|     nav-border-color: $middle-light, | ||||
|     error-color: $p5js-pink, | ||||
|     table-row-stripe-color: $medium-light, | ||||
|     table-row-stripe-color-alternate: $medium-light, | ||||
|     codefold-icon-open: url(../images/triangle-arrow-down.svg?byUrl), | ||||
|     codefold-icon-closed: url(../images/triangle-arrow-right.svg?byUrl), | ||||
| 
 | ||||
|  | @ -163,6 +164,7 @@ $themes: ( | |||
|     nav-border-color: $middle-dark, | ||||
|     error-color: $p5js-pink, | ||||
|     table-row-stripe-color: $dark, | ||||
|     table-row-stripe-color-alternate: $darker, | ||||
|     codefold-icon-open: url(../images/triangle-arrow-down-white.svg?byUrl), | ||||
|     codefold-icon-closed: url(../images/triangle-arrow-right-white.svg?byUrl), | ||||
| 
 | ||||
|  | @ -236,6 +238,7 @@ $themes: ( | |||
|     nav-border-color: $middle-dark, | ||||
|     error-color: $p5-contrast-pink, | ||||
|     table-row-stripe-color: $dark, | ||||
|     table-row-stripe-color-alternate: $darker, | ||||
|     codefold-icon-open: url(../images/triangle-arrow-down-white.svg?byUrl), | ||||
|     codefold-icon-closed: url(../images/triangle-arrow-right-white.svg?byUrl), | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,16 @@ | |||
| .quick-add-wrapper { | ||||
|   min-width: #{600 / $base-font-size}rem; | ||||
|   overflow-y: scroll; | ||||
|   padding: #{24 / $base-font-size}rem; | ||||
|   height: 100%; | ||||
| } | ||||
| 
 | ||||
| .quick-add { | ||||
|   width: auto; | ||||
|   padding: #{24 / $base-font-size}rem; | ||||
|   overflow-y: scroll; | ||||
|   height: 100%; | ||||
|   @include themify() { | ||||
|     border: 1px solid getThemifyVariable('modal-border-color'); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .quick-add__item { | ||||
|  | @ -23,7 +28,7 @@ | |||
| 
 | ||||
| .quick-add__item:nth-child(odd) { | ||||
|   @include themify() { | ||||
|     background: getThemifyVariable('table-row-stripe-color'); | ||||
|     background: getThemifyVariable('table-row-stripe-color-alternate'); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -174,15 +174,33 @@ | |||
|     } | ||||
|   }, | ||||
|   "Sidebar": { | ||||
|     "Create": "Create", | ||||
|     "EnterName": "enter a name", | ||||
|     "Add": "Add", | ||||
|     "Folder": "Folder" | ||||
|     "Title": "Sketch Files", | ||||
|     "ToggleARIA": "Toggle open/close sketch file options", | ||||
|     "AddFolder": "Create folder", | ||||
|     "AddFolderARIA": "add folder", | ||||
|     "AddFile": "Create file", | ||||
|     "AddFileARIA": "add file", | ||||
|     "UploadFile": "Upload file", | ||||
|     "UploadFileARIA": "upload file" | ||||
|   }, | ||||
|   "FileNode": { | ||||
|     "OpenFolderARIA": "Open folder contents", | ||||
|     "CloseFolderARIA": "Close folder contents", | ||||
|     "ToggleFileOptionsARIA": "Toggle open/close file options", | ||||
|     "AddFolder": "Create folder", | ||||
|     "AddFolderARIA": "add folder", | ||||
|     "AddFile": "Create file", | ||||
|     "AddFileARIA": "add file", | ||||
|     "UploadFile": "Upload file", | ||||
|     "UploadFileARIA": "upload file", | ||||
|     "Rename": "Rename", | ||||
|     "Delete": "Delete" | ||||
|   }, | ||||
|   "Common": { | ||||
|     "Error": "Error", | ||||
|     "Save": "Save", | ||||
|     "p5logoARIA": "p5.js Logo" | ||||
|     "p5logoARIA": "p5.js Logo", | ||||
|     "DeleteConfirmation": "Are you sure you want to delete {{name}}?" | ||||
|   }, | ||||
|   "IDEView": { | ||||
|     "SubmitFeedback": "Submit Feedback" | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Cassie Tarakajian
						Cassie Tarakajian