Skip to content

Commit 2349acc

Browse files
authored
Merge branch 'develop' into feature/mobile-save-sketch
2 parents 5f24a71 + 45a4e54 commit 2349acc

File tree

11 files changed

+125
-59
lines changed

11 files changed

+125
-59
lines changed

client/jest.setup.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,21 @@ import '@babel/polyfill';
33
// See: https://github.com/testing-library/jest-dom
44
// eslint-disable-next-line import/no-extraneous-dependencies
55
import '@testing-library/jest-dom';
6+
7+
import lodash from 'lodash';
8+
9+
// For testing, we use en-US and provide a mock implementation
10+
// of t() that finds the correct translation
11+
import translations from '../translations/locales/en-US/translations.json';
12+
13+
// This function name needs to be prefixed with "mock" so that Jest doesn't
14+
// complain that it's out-of-scope in the mock below
15+
const mockTranslate = key => lodash.get(translations, key);
16+
17+
jest.mock('react-i18next', () => ({
18+
// this mock makes sure any components using the translate HoC receive the t function as a prop
19+
withTranslation: () => (Component) => {
20+
Component.defaultProps = { ...Component.defaultProps, t: mockTranslate };
21+
return Component;
22+
},
23+
}));

client/modules/IDE/components/AddToCollectionList.jsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import Loader from '../../App/components/loader';
1414
import QuickAddList from './QuickAddList';
1515

1616
const projectInCollection = (project, collection) =>
17-
collection.items.find(item => item.project.id === project.id) != null;
17+
collection.items.find(item => item.projectId === project.id) != null;
1818

1919
class CollectionList extends React.Component {
2020
constructor(props) {
@@ -81,12 +81,14 @@ class CollectionList extends React.Component {
8181
}
8282

8383
return (
84-
<div className="quick-add-wrapper">
85-
<Helmet>
86-
<title>{this.getTitle()}</title>
87-
</Helmet>
88-
89-
{content}
84+
<div className="collection-add-sketch">
85+
<div className="quick-add-wrapper">
86+
<Helmet>
87+
<title>{this.getTitle()}</title>
88+
</Helmet>
89+
90+
{content}
91+
</div>
9092
</div>
9193
);
9294
}

client/modules/IDE/components/AddToCollectionSketchList.jsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,13 @@ class SketchList extends React.Component {
7272
}
7373

7474
return (
75-
<div className="quick-add-wrapper">
76-
<Helmet>
77-
<title>{this.getSketchesTitle()}</title>
78-
</Helmet>
79-
{content}
75+
<div className="collection-add-sketch">
76+
<div className="quick-add-wrapper">
77+
<Helmet>
78+
<title>{this.getSketchesTitle()}</title>
79+
</Helmet>
80+
{content}
81+
</div>
8082
</div>
8183
);
8284
}

client/modules/IDE/components/CollectionList/CollectionList.jsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,10 @@ class CollectionList extends React.Component {
170170
closeOverlay={this.hideAddSketches}
171171
isFixedHeight
172172
>
173-
<div className="collection-add-sketch">
174-
<AddToCollectionSketchList
175-
username={this.props.username}
176-
collection={find(this.props.collections, { id: this.state.addingSketchesToCollectionId })}
177-
/>
178-
</div>
173+
<AddToCollectionSketchList
174+
username={this.props.username}
175+
collection={find(this.props.collections, { id: this.state.addingSketchesToCollectionId })}
176+
/>
179177
</Overlay>
180178
)
181179
}

client/modules/IDE/components/Console.jsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import React, { useRef } from 'react';
2+
import PropTypes from 'prop-types';
3+
import { withTranslation } from 'react-i18next';
24

35
import { bindActionCreators } from 'redux';
46

@@ -72,7 +74,7 @@ const getConsoleFeedStyle = (theme, times, fontSize) => {
7274
}
7375
};
7476

75-
const Console = () => {
77+
const Console = ({ t }) => {
7678
const consoleEvents = useSelector(state => state.console);
7779
const isExpanded = useSelector(state => state.ide.consoleIsExpanded);
7880
const { theme, fontSize } = useSelector(state => state.preferences);
@@ -98,19 +100,19 @@ const Console = () => {
98100
return (
99101
<section className={consoleClass} >
100102
<header className="preview-console__header">
101-
<h2 className="preview-console__header-title">Console</h2>
103+
<h2 className="preview-console__header-title">{t('Console.Title')}</h2>
102104
<div className="preview-console__header-buttons">
103-
<button className="preview-console__clear" onClick={clearConsole} aria-label="Clear console">
104-
Clear
105+
<button className="preview-console__clear" onClick={clearConsole} aria-label={t('Console.ClearARIA')}>
106+
{t('Console.Clear')}
105107
</button>
106108
<button
107109
className="preview-console__collapse"
108110
onClick={collapseConsole}
109-
aria-label="Close console"
111+
aria-label={t('Console.CloseARIA')}
110112
>
111113
<DownArrowIcon focusable="false" aria-hidden="true" />
112114
</button>
113-
<button className="preview-console__expand" onClick={expandConsole} aria-label="Open console" >
115+
<button className="preview-console__expand" onClick={expandConsole} aria-label={t('Console.OpenARIA')} >
114116
<UpArrowIcon focusable="false" aria-hidden="true" />
115117
</button>
116118
</div>
@@ -140,5 +142,9 @@ const Console = () => {
140142
);
141143
};
142144

145+
Console.propTypes = {
146+
t: PropTypes.func.isRequired,
147+
};
148+
143149

144-
export default Console;
150+
export default withTranslation()(Console);

client/modules/IDE/components/FileNode.jsx

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import React from 'react';
33
import { bindActionCreators } from 'redux';
44
import { connect } from 'react-redux';
55
import classNames from 'classnames';
6+
import { withTranslation } from 'react-i18next';
7+
68
import * as IDEActions from '../actions/ide';
79
import * as FileActions from '../actions/files';
810
import DownArrowIcon from '../../../images/down-filled-triangle.svg';
@@ -152,7 +154,9 @@ export class FileNode extends React.Component {
152154
}
153155

154156
handleClickDelete = () => {
155-
if (window.confirm(`Are you sure you want to delete ${this.props.name}?`)) {
157+
const prompt = this.props.t('Common.DeleteConfirmation', { name: this.props.name });
158+
159+
if (window.confirm(prompt)) {
156160
this.setState({ isDeleting: true });
157161
this.props.resetSelectedFile(this.props.id);
158162
setTimeout(() => this.props.deleteFile(this.props.id, this.props.parentId), 100);
@@ -237,6 +241,8 @@ export class FileNode extends React.Component {
237241
const isFolder = this.props.fileType === 'folder';
238242
const isRoot = this.props.name === 'root';
239243

244+
const { t } = this.props;
245+
240246
return (
241247
<div className={itemClass} >
242248
{ !isRoot &&
@@ -252,14 +258,14 @@ export class FileNode extends React.Component {
252258
<button
253259
className="sidebar__file-item-closed"
254260
onClick={this.showFolderChildren}
255-
aria-label="Open folder contents"
261+
aria-label={t('FileNode.OpenFolderARIA')}
256262
>
257263
<FolderRightIcon className="folder-right" focusable="false" aria-hidden="true" />
258264
</button>
259265
<button
260266
className="sidebar__file-item-open"
261267
onClick={this.hideFolderChildren}
262-
aria-label="Close file contents"
268+
aria-label={t('FileNode.CloseFolderARIA')}
263269
>
264270
<FolderDownIcon className="folder-down" focusable="false" aria-hidden="true" />
265271
</button>
@@ -286,7 +292,7 @@ export class FileNode extends React.Component {
286292
/>
287293
<button
288294
className="sidebar__file-item-show-options"
289-
aria-label="Toggle open/close file options"
295+
aria-label={t('FileNode.ToggleFileOptionsARIA')}
290296
ref={(element) => { this[`fileOptions-${this.props.id}`] = element; }}
291297
tabIndex="0"
292298
onClick={this.toggleFileOptions}
@@ -301,35 +307,35 @@ export class FileNode extends React.Component {
301307
<React.Fragment>
302308
<li>
303309
<button
304-
aria-label="add folder"
310+
aria-label={t('FileNode.AddFolderARIA')}
305311
onClick={this.handleClickAddFolder}
306312
onBlur={this.onBlurComponent}
307313
onFocus={this.onFocusComponent}
308314
className="sidebar__file-item-option"
309315
>
310-
Create folder
316+
{t('FileNode.AddFolder')}
311317
</button>
312318
</li>
313319
<li>
314320
<button
315-
aria-label="add file"
321+
aria-label={t('FileNode.AddFileARIA')}
316322
onClick={this.handleClickAddFile}
317323
onBlur={this.onBlurComponent}
318324
onFocus={this.onFocusComponent}
319325
className="sidebar__file-item-option"
320326
>
321-
Create file
327+
{t('FileNode.AddFile')}
322328
</button>
323329
</li>
324330
{ this.props.authenticated &&
325331
<li>
326332
<button
327-
aria-label="upload file"
333+
aria-label={t('FileNode.UploadFileARIA')}
328334
onClick={this.handleClickUploadFile}
329335
onBlur={this.onBlurComponent}
330336
onFocus={this.onFocusComponent}
331337
>
332-
Upload file
338+
{t('FileNode.UploadFile')}
333339
</button>
334340
</li>
335341
}
@@ -342,7 +348,7 @@ export class FileNode extends React.Component {
342348
onFocus={this.onFocusComponent}
343349
className="sidebar__file-item-option"
344350
>
345-
Rename
351+
{t('FileNode.Rename')}
346352
</button>
347353
</li>
348354
<li>
@@ -352,7 +358,7 @@ export class FileNode extends React.Component {
352358
onFocus={this.onFocusComponent}
353359
className="sidebar__file-item-option"
354360
>
355-
Delete
361+
{t('FileNode.Delete')}
356362
</button>
357363
</li>
358364
</ul>
@@ -388,6 +394,7 @@ FileNode.propTypes = {
388394
canEdit: PropTypes.bool.isRequired,
389395
openUploadFileModal: PropTypes.func.isRequired,
390396
authenticated: PropTypes.bool.isRequired,
397+
t: PropTypes.func.isRequired,
391398
onClickFile: PropTypes.func
392399
};
393400

@@ -408,5 +415,8 @@ function mapDispatchToProps(dispatch) {
408415
return bindActionCreators(Object.assign(FileActions, IDEActions), dispatch);
409416
}
410417

411-
const ConnectedFileNode = connect(mapStateToProps, mapDispatchToProps)(FileNode);
418+
const TranslatedFileNode = withTranslation()(FileNode);
419+
420+
const ConnectedFileNode = connect(mapStateToProps, mapDispatchToProps)(TranslatedFileNode);
421+
412422
export default ConnectedFileNode;

client/modules/IDE/components/Sidebar.jsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import PropTypes from 'prop-types';
22
import React from 'react';
33
import classNames from 'classnames';
4+
import { withTranslation } from 'react-i18next';
5+
46
import ConnectedFileNode from './FileNode';
57

68
import DownArrowIcon from '../../../images/down-filled-triangle.svg';
@@ -71,11 +73,11 @@ class Sidebar extends React.Component {
7173
<section className={sidebarClass}>
7274
<header className="sidebar__header" onContextMenu={this.toggleProjectOptions}>
7375
<h3 className="sidebar__title">
74-
<span>Sketch Files</span>
76+
<span>{this.props.t('Sidebar.Title')}</span>
7577
</h3>
7678
<div className="sidebar__icons">
7779
<button
78-
aria-label="Toggle open/close sketch file options"
80+
aria-label={this.props.t('Sidebar.ToggleARIA')}
7981
className="sidebar__add"
8082
tabIndex="0"
8183
ref={(element) => { this.sidebarOptions = element; }}
@@ -88,43 +90,43 @@ class Sidebar extends React.Component {
8890
<ul className="sidebar__project-options">
8991
<li>
9092
<button
91-
aria-label="add folder"
93+
aria-label={this.props.t('Sidebar.AddFolderARIA')}
9294
onClick={() => {
9395
this.props.newFolder(rootFile.id);
9496
setTimeout(this.props.closeProjectOptions, 0);
9597
}}
9698
onBlur={this.onBlurComponent}
9799
onFocus={this.onFocusComponent}
98100
>
99-
Create folder
101+
{this.props.t('Sidebar.AddFolder')}
100102
</button>
101103
</li>
102104
<li>
103105
<button
104-
aria-label="add file"
106+
aria-label={this.props.t('Sidebar.AddFileARIA')}
105107
onClick={() => {
106108
this.props.newFile(rootFile.id);
107109
setTimeout(this.props.closeProjectOptions, 0);
108110
}}
109111
onBlur={this.onBlurComponent}
110112
onFocus={this.onFocusComponent}
111113
>
112-
Create file
114+
{this.props.t('Sidebar.AddFile')}
113115
</button>
114116
</li>
115117
{
116118
this.props.user.authenticated &&
117119
<li>
118120
<button
119-
aria-label="upload file"
121+
aria-label={this.props.t('Sidebar.UploadFileARIA')}
120122
onClick={() => {
121123
this.props.openUploadFileModal(rootFile.id);
122124
setTimeout(this.props.closeProjectOptions, 0);
123125
}}
124126
onBlur={this.onBlurComponent}
125127
onFocus={this.onFocusComponent}
126128
>
127-
Upload file
129+
{this.props.t('Sidebar.UploadFile')}
128130
</button>
129131
</li>
130132
}
@@ -159,11 +161,12 @@ Sidebar.propTypes = {
159161
user: PropTypes.shape({
160162
id: PropTypes.string,
161163
authenticated: PropTypes.bool.isRequired
162-
}).isRequired
164+
}).isRequired,
165+
t: PropTypes.func.isRequired,
163166
};
164167

165168
Sidebar.defaultProps = {
166169
owner: undefined
167170
};
168171

169-
export default Sidebar;
172+
export default withTranslation()(Sidebar);

client/modules/User/components/Collection.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,10 @@ class Collection extends React.Component {
398398
closeOverlay={this.hideAddSketches}
399399
isFixedHeight
400400
>
401-
<div className="collection-add-sketch">
402-
<AddToCollectionSketchList username={this.props.username} collection={this.props.collection} />
403-
</div>
401+
<AddToCollectionSketchList
402+
username={this.props.username}
403+
collection={this.props.collection}
404+
/>
404405
</Overlay>
405406
)
406407
}

client/styles/abstracts/_variables.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ $themes: (
8888
nav-border-color: $middle-light,
8989
error-color: $p5js-pink,
9090
table-row-stripe-color: $medium-light,
91+
table-row-stripe-color-alternate: $medium-light,
9192
codefold-icon-open: url(../images/triangle-arrow-down.svg?byUrl),
9293
codefold-icon-closed: url(../images/triangle-arrow-right.svg?byUrl),
9394

@@ -163,6 +164,7 @@ $themes: (
163164
nav-border-color: $middle-dark,
164165
error-color: $p5js-pink,
165166
table-row-stripe-color: $dark,
167+
table-row-stripe-color-alternate: $darker,
166168
codefold-icon-open: url(../images/triangle-arrow-down-white.svg?byUrl),
167169
codefold-icon-closed: url(../images/triangle-arrow-right-white.svg?byUrl),
168170

@@ -236,6 +238,7 @@ $themes: (
236238
nav-border-color: $middle-dark,
237239
error-color: $p5-contrast-pink,
238240
table-row-stripe-color: $dark,
241+
table-row-stripe-color-alternate: $darker,
239242
codefold-icon-open: url(../images/triangle-arrow-down-white.svg?byUrl),
240243
codefold-icon-closed: url(../images/triangle-arrow-right-white.svg?byUrl),
241244

0 commit comments

Comments
 (0)