Skip to content

Commit 5b3d4d3

Browse files
committed
Merge develop
2 parents 12cb0a5 + b7d17a0 commit 5b3d4d3

File tree

23 files changed

+369
-332
lines changed

23 files changed

+369
-332
lines changed

client/common/icons.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Preferences from '../images/preferences.svg';
1414
import Play from '../images/triangle-arrow-right.svg';
1515
import More from '../images/more.svg';
1616
import Code from '../images/code.svg';
17+
import Save from '../images/save.svg';
1718
import Terminal from '../images/terminal.svg';
1819

1920
import Folder from '../images/folder-padded.svg';
@@ -87,6 +88,7 @@ export const PlayIcon = withLabel(Play);
8788
export const MoreIcon = withLabel(More);
8889
export const TerminalIcon = withLabel(Terminal);
8990
export const CodeIcon = withLabel(Code);
91+
export const SaveIcon = withLabel(Save);
9092

9193
export const FolderIcon = withLabel(Folder);
9294

client/components/Nav.jsx

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { withRouter } from 'react-router';
55
import { Link } from 'react-router';
66
import classNames from 'classnames';
77
import { withTranslation } from 'react-i18next';
8-
import i18next from 'i18next';
8+
import { languageKeyToLabel } from '../i18n';
99
import * as IDEActions from '../modules/IDE/actions/ide';
1010
import * as toastActions from '../modules/IDE/actions/toast';
1111
import * as projectActions from '../modules/IDE/actions/project';
@@ -549,7 +549,7 @@ class Nav extends React.PureComponent {
549549

550550
renderLanguageMenu(navDropdownState) {
551551
return (
552-
<ul className="nav__items-right" title="user-menu">
552+
<React.Fragment>
553553
<li className={navDropdownState.lang}>
554554
<button
555555
onClick={this.toggleDropdownForLang}
@@ -561,21 +561,11 @@ class Nav extends React.PureComponent {
561561
}
562562
}}
563563
>
564-
<span className="nav__item-header"> {this.props.t('Nav.Lang')}</span>
564+
<span className="nav__item-header"> {languageKeyToLabel(this.props.language)}</span>
565565
<TriangleIcon className="nav__item-header-triangle" focusable="false" aria-hidden="true" />
566566
</button>
567567
<ul className="nav__dropdown">
568568

569-
<li className="nav__dropdown-item">
570-
<button
571-
onFocus={this.handleFocusForLang}
572-
onBlur={this.handleBlur}
573-
value="it"
574-
onClick={e => this.handleLangSelection(e)}
575-
>
576-
Italian (Test Fallback)
577-
</button>
578-
</li>
579569
<li className="nav__dropdown-item">
580570
<button
581571
onFocus={this.handleFocusForLang}
@@ -597,14 +587,15 @@ class Nav extends React.PureComponent {
597587
</li>
598588
</ul>
599589
</li>
600-
</ul>
590+
</React.Fragment>
601591
);
602592
}
603593

604594

605595
renderUnauthenticatedUserMenu(navDropdownState) {
606596
return (
607597
<ul className="nav__items-right" title="user-menu">
598+
{getConfig('TRANSLATIONS_ENABLED') && this.renderLanguageMenu(navDropdownState)}
608599
<li className="nav__item">
609600
<Link to="/login" className="nav__auth-button">
610601
<span className="nav__item-header">{this.props.t('Nav.Login')}</span>
@@ -623,10 +614,7 @@ class Nav extends React.PureComponent {
623614
renderAuthenticatedUserMenu(navDropdownState) {
624615
return (
625616
<ul className="nav__items-right" title="user-menu">
626-
<li className="nav__item">
627-
<span>{this.props.t('Nav.Auth.Hello')}, {this.props.user.username}!</span>
628-
</li>
629-
<span className="nav__item-spacer">|</span>
617+
{getConfig('TRANSLATIONS_ENABLED') && this.renderLanguageMenu(navDropdownState)}
630618
<li className={navDropdownState.account}>
631619
<button
632620
className="nav__item-header"
@@ -639,7 +627,7 @@ class Nav extends React.PureComponent {
639627
}
640628
}}
641629
>
642-
{this.props.t('Nav.Auth.MyAccount')}
630+
<span>{this.props.t('Nav.Auth.Hello')}, {this.props.user.username}!</span>
643631
<TriangleIcon className="nav__item-header-triangle" focusable="false" aria-hidden="true" />
644632
</button>
645633
<ul className="nav__dropdown">
@@ -755,7 +743,6 @@ class Nav extends React.PureComponent {
755743
<header>
756744
<nav className="nav" title="main-navigation" ref={(node) => { this.node = node; }}>
757745
{this.renderLeftLayout(navDropdownState)}
758-
{getConfig('TRANSLATIONS_ENABLED') && this.renderLanguageMenu(navDropdownState)}
759746
{this.renderUserMenu(navDropdownState)}
760747
</nav>
761748
</header>
@@ -809,6 +796,7 @@ Nav.propTypes = {
809796
}),
810797
t: PropTypes.func.isRequired,
811798
setLanguage: PropTypes.func.isRequired,
799+
language: PropTypes.string.isRequired,
812800
};
813801

814802
Nav.defaultProps = {
@@ -829,7 +817,8 @@ function mapStateToProps(state) {
829817
project: state.project,
830818
user: state.user,
831819
unsavedChanges: state.ide.unsavedChanges,
832-
rootFile: state.files.filter(file => file.name === 'root')[0]
820+
rootFile: state.files.filter(file => file.name === 'root')[0],
821+
language: state.preferences.language
833822
};
834823
}
835824

client/components/NavBasic.jsx

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

45
import LogoIcon from '../images/p5js-logo-small.svg';
56
import ArrowIcon from '../images/triangle-arrow-left.svg';
@@ -14,7 +15,7 @@ class NavBasic extends React.PureComponent {
1415
<nav className="nav" title="main-navigation" ref={(node) => { this.node = node; }}>
1516
<ul className="nav__items-left">
1617
<li className="nav__item-logo">
17-
<LogoIcon role="img" aria-label="p5.js Logo" focusable="false" className="svg__logo" />
18+
<LogoIcon role="img" aria-label={this.props.t('Common.p5logoARIA')} focusable="false" className="svg__logo" />
1819
</li>
1920
{ this.props.onBack && (
2021
<li className="nav__item">
@@ -34,6 +35,7 @@ class NavBasic extends React.PureComponent {
3435

3536
NavBasic.propTypes = {
3637
onBack: PropTypes.func,
38+
t: PropTypes.func.isRequired
3739
};
3840

39-
export default NavBasic;
41+
export default withTranslation()(NavBasic);

client/components/__test__/Nav.test.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ describe('Nav', () => {
4646
id: 'root-file'
4747
},
4848
t: jest.fn(),
49-
setLanguage: jest.fn()
49+
setLanguage: jest.fn(),
50+
language: 'en-US'
5051
};
5152

5253
it('renders correctly', () => {
Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
import React from 'react';
2-
import styled from 'styled-components';
32
import PropTypes from 'prop-types';
4-
import { bindActionCreators } from 'redux';
5-
import { useDispatch, useSelector } from 'react-redux';
3+
import styled from 'styled-components';
64
import { remSize, prop } from '../../theme';
75
import IconButton from './IconButton';
8-
import { TerminalIcon, FolderIcon } from '../../common/icons';
9-
import * as IDEActions from '../../modules/IDE/actions/ide';
106

117
const BottomBarContent = styled.div`
128
padding: ${remSize(8)};
13-
display: flex;
9+
display: grid;
10+
grid-template-columns: repeat(8,1fr);
1411
1512
svg {
1613
max-height: ${remSize(32)};
17-
1814
}
1915
2016
path { fill: ${prop('primaryTextColor')} !important }
@@ -25,42 +21,28 @@ const BottomBarContent = styled.div`
2521
}
2622
`;
2723

28-
// Maybe this component shouldn't be connected, and instead just receive the `actions` prop
29-
const ActionStrip = ({ toggleExplorer }) => {
30-
const { expandConsole, collapseConsole } = bindActionCreators(IDEActions, useDispatch());
31-
const { consoleIsExpanded } = useSelector(state => state.ide);
32-
33-
const actions = [
34-
{
35-
icon: TerminalIcon, inverted: true, aria: 'Open terminal console', action: consoleIsExpanded ? collapseConsole : expandConsole
36-
},
37-
{ icon: FolderIcon, aria: 'Open files explorer', action: toggleExplorer }
38-
];
39-
40-
return (
41-
<BottomBarContent>
42-
{actions.map(({
43-
icon, aria, action, inverted
44-
}) =>
45-
(
46-
<IconButton
47-
inverted={inverted}
48-
className={inverted && 'inverted'}
49-
icon={icon}
50-
aria-label={aria}
51-
key={`bottom-bar-${aria}`}
52-
onClick={() => action()}
53-
/>))}
54-
</BottomBarContent>
55-
);
56-
};
24+
const ActionStrip = ({ actions }) => (
25+
<BottomBarContent>
26+
{actions.map(({
27+
icon, aria, action, inverted
28+
}) =>
29+
(<IconButton
30+
inverted={inverted}
31+
className={inverted && 'inverted'}
32+
icon={icon}
33+
aria-label={aria}
34+
key={`bottom-bar-${aria}`}
35+
onClick={action}
36+
/>))}
37+
</BottomBarContent>);
5738

5839
ActionStrip.propTypes = {
59-
toggleExplorer: PropTypes.func
60-
};
61-
62-
ActionStrip.defaultProps = {
63-
toggleExplorer: () => {}
40+
actions: PropTypes.arrayOf(PropTypes.shape({
41+
icon: PropTypes.any,
42+
aria: PropTypes.string.isRequired,
43+
action: PropTypes.func.isRequired,
44+
inverted: PropTypes.bool
45+
})).isRequired
6446
};
6547

6648
export default ActionStrip;

client/components/mobile/Header.jsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ const HeaderDiv = styled.div`
3535
}
3636
3737
& svg path { fill: ${textColor} !important; }
38+
39+
.editor__unsaved-changes svg {
40+
width: ${remSize(16)};
41+
padding: 0;
42+
vertical-align: top
43+
}
3844
`;
3945

4046
const IconContainer = styled.div`
@@ -71,8 +77,9 @@ const Header = ({
7177
</HeaderDiv>
7278
);
7379

80+
7481
Header.propTypes = {
75-
title: PropTypes.string,
82+
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
7683
subtitle: PropTypes.string,
7784
leftButton: PropTypes.element,
7885
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),

client/components/mobile/Sidebar.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const SidebarWrapper = styled.div`
1616
z-index: 2;
1717
left: 0;
1818
19-
background: white;
19+
background: ${prop('backgroundColor')};
2020
box-shadow: 0 6px 6px 0 rgba(0,0,0,0.10);
2121
`;
2222

client/i18n.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ import Backend from 'i18next-http-backend';
66
const fallbackLng = ['en-US'];
77
const availableLanguages = ['en-US', 'es-419'];
88

9+
export function languageKeyToLabel(lang) {
10+
const languageMap = {
11+
'en-US': 'English',
12+
'es-419': 'Español'
13+
};
14+
return languageMap[lang];
15+
}
16+
917
const options = {
1018
loadPath: '/locales/{{lng}}/translations.json',
1119
requestOptions: { // used for fetch, can also be a function (payload) => ({ method: 'GET' })

client/images/save.svg

Lines changed: 3 additions & 0 deletions
Loading

client/modules/IDE/actions/project.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ function getSynchedProject(currentState, responseProject) {
126126
};
127127
}
128128

129-
export function saveProject(selectedFile = null, autosave = false) {
129+
export function saveProject(selectedFile = null, autosave = false, mobile = false) {
130130
return (dispatch, getState) => {
131131
const state = getState();
132132
if (state.project.isSaving) {
@@ -185,16 +185,15 @@ export function saveProject(selectedFile = null, autosave = false) {
185185
.then((response) => {
186186
dispatch(endSavingProject());
187187
const { hasChanges, synchedProject } = getSynchedProject(getState(), response.data);
188+
189+
dispatch(setNewProject(synchedProject));
190+
dispatch(setUnsavedChanges(false));
191+
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
192+
188193
if (hasChanges) {
189-
dispatch(setNewProject(synchedProject));
190-
dispatch(setUnsavedChanges(false));
191-
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
192194
dispatch(setUnsavedChanges(true));
193-
} else {
194-
dispatch(setNewProject(synchedProject));
195-
dispatch(setUnsavedChanges(false));
196-
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
197195
}
196+
198197
dispatch(projectSaveSuccess());
199198
if (!autosave) {
200199
if (state.preferences.autosave) {
@@ -222,9 +221,9 @@ export function saveProject(selectedFile = null, autosave = false) {
222221
};
223222
}
224223

225-
export function autosaveProject() {
224+
export function autosaveProject(mobile = false) {
226225
return (dispatch, getState) => {
227-
saveProject(null, true)(dispatch, getState);
226+
saveProject(null, true, mobile)(dispatch, getState);
228227
};
229228
}
230229

0 commit comments

Comments
 (0)