Skip to content

Commit 0761cf9

Browse files
Merge pull request #1 from processing/develop
Update from original
2 parents 3253770 + 093c8ff commit 0761cf9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1704
-538
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ S3_BUCKET_URL_BASE=<alt-for-s3-url>
2626
SESSION_SECRET=whatever_you_want_this_to_be_it_only_matters_for_production
2727
UI_ACCESS_TOKEN_ENABLED=false
2828
UPLOAD_LIMIT=250000000
29+
MOBILE_ENABLED=true

client/common/icons.jsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ import More from '../images/more.svg';
1616
import Code from '../images/code.svg';
1717
import Terminal from '../images/terminal.svg';
1818

19+
import Folder from '../images/folder-padded.svg';
20+
21+
import CircleTerminal from '../images/circle-terminal.svg';
22+
import CircleFolder from '../images/circle-folder.svg';
23+
import CircleInfo from '../images/circle-info.svg';
24+
1925

2026
// HOC that adds the right web accessibility props
2127
// https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html
@@ -81,3 +87,9 @@ export const PlayIcon = withLabel(Play);
8187
export const MoreIcon = withLabel(More);
8288
export const TerminalIcon = withLabel(Terminal);
8389
export const CodeIcon = withLabel(Code);
90+
91+
export const FolderIcon = withLabel(Folder);
92+
93+
export const CircleTerminalIcon = withLabel(CircleTerminal);
94+
export const CircleFolderIcon = withLabel(CircleFolder);
95+
export const CircleInfoIcon = withLabel(CircleInfo);

client/components/Dropdown.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const DropdownWrapper = styled.ul`
2525
display: flex;
2626
flex-direction: column;
2727
height: auto;
28-
z-index: 9999;
28+
z-index: 2;
2929
border-radius: ${remSize(6)};
3030
3131
& li:first-child { border-radius: ${remSize(5)} ${remSize(5)} 0 0; }

client/components/Nav.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import i18next from 'i18next';
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';
12-
import { setAllAccessibleOutput } from '../modules/IDE/actions/preferences';
12+
import { setAllAccessibleOutput, setLanguage } from '../modules/IDE/actions/preferences';
1313
import { logoutUser } from '../modules/User/actions';
1414

1515
import getConfig from '../utils/getConfig';
@@ -72,7 +72,6 @@ class Nav extends React.PureComponent {
7272
document.removeEventListener('mousedown', this.handleClick, false);
7373
document.removeEventListener('keydown', this.closeDropDown, false);
7474
}
75-
7675
setDropdown(dropdown) {
7776
this.setState({
7877
dropdownOpen: dropdown
@@ -170,7 +169,7 @@ class Nav extends React.PureComponent {
170169
}
171170

172171
handleLangSelection(event) {
173-
i18next.changeLanguage(event.target.value);
172+
this.props.setLanguage(event.target.value);
174173
this.props.showToast(1500);
175174
this.props.setToastText('Toast.LangChange');
176175
this.setDropdown('none');
@@ -608,13 +607,13 @@ class Nav extends React.PureComponent {
608607
<ul className="nav__items-right" title="user-menu">
609608
<li className="nav__item">
610609
<Link to="/login" className="nav__auth-button">
611-
<span className="nav__item-header">{this.props.t('Nav.Login.Login')}</span>
610+
<span className="nav__item-header">{this.props.t('Nav.Login')}</span>
612611
</Link>
613612
</li>
614-
<span className="nav__item-or">{this.props.t('Nav.Login.LoginOr')}</span>
613+
<span className="nav__item-or">{this.props.t('Nav.LoginOr')}</span>
615614
<li className="nav__item">
616615
<Link to="/signup" className="nav__auth-button">
617-
<span className="nav__item-header">{this.props.t('Nav.Login.SignUp')}</span>
616+
<span className="nav__item-header">{this.props.t('Nav.SignUp')}</span>
618617
</Link>
619618
</li>
620619
</ul>
@@ -808,8 +807,8 @@ Nav.propTypes = {
808807
params: PropTypes.shape({
809808
username: PropTypes.string
810809
}),
811-
t: PropTypes.func.isRequired
812-
810+
t: PropTypes.func.isRequired,
811+
setLanguage: PropTypes.func.isRequired,
813812
};
814813

815814
Nav.defaultProps = {
@@ -839,7 +838,8 @@ const mapDispatchToProps = {
839838
...projectActions,
840839
...toastActions,
841840
logoutUser,
842-
setAllAccessibleOutput
841+
setAllAccessibleOutput,
842+
setLanguage
843843
};
844844

845845
export default withTranslation()(withRouter(connect(mapStateToProps, mapDispatchToProps)(Nav)));

client/components/__test__/Nav.test.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ describe('Nav', () => {
4545
rootFile: {
4646
id: 'root-file'
4747
},
48-
t: jest.fn()
48+
t: jest.fn(),
49+
setLanguage: jest.fn()
4950
};
5051

5152
it('renders correctly', () => {
Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,66 @@
11
import React from 'react';
22
import styled from 'styled-components';
3+
import PropTypes from 'prop-types';
34
import { bindActionCreators } from 'redux';
45
import { useDispatch, useSelector } from 'react-redux';
5-
import { remSize } from '../../theme';
6+
import { remSize, prop } from '../../theme';
67
import IconButton from './IconButton';
7-
import { TerminalIcon } from '../../common/icons';
8+
import { TerminalIcon, FolderIcon } from '../../common/icons';
89
import * as IDEActions from '../../modules/IDE/actions/ide';
910

10-
const BottomBarContent = styled.h2`
11+
const BottomBarContent = styled.div`
1112
padding: ${remSize(8)};
12-
13+
display: flex;
14+
1315
svg {
1416
max-height: ${remSize(32)};
17+
18+
}
19+
20+
path { fill: ${prop('primaryTextColor')} !important }
21+
22+
.inverted {
23+
path { fill: ${prop('backgroundColor')} !important }
24+
rect { fill: ${prop('primaryTextColor')} !important }
1525
}
1626
`;
1727

18-
export default () => {
28+
// Maybe this component shouldn't be connected, and instead just receive the `actions` prop
29+
const ActionStrip = ({ toggleExplorer }) => {
1930
const { expandConsole, collapseConsole } = bindActionCreators(IDEActions, useDispatch());
2031
const { consoleIsExpanded } = useSelector(state => state.ide);
2132

22-
const actions = [{ icon: TerminalIcon, aria: 'Say Something', action: consoleIsExpanded ? collapseConsole : expandConsole }];
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+
];
2339

2440
return (
2541
<BottomBarContent>
26-
{actions.map(({ icon, aria, action }) =>
27-
(<IconButton
28-
icon={icon}
29-
aria-label={aria}
30-
key={`bottom-bar-${aria}`}
31-
onClick={() => action()}
32-
/>))}
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+
/>))}
3354
</BottomBarContent>
3455
);
3556
};
57+
58+
ActionStrip.propTypes = {
59+
toggleExplorer: PropTypes.func
60+
};
61+
62+
ActionStrip.defaultProps = {
63+
toggleExplorer: () => {}
64+
};
65+
66+
export default ActionStrip;

client/components/mobile/Explorer.jsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
import PropTypes from 'prop-types';
4+
import Sidebar from './Sidebar';
5+
import ConnectedFileNode from '../../modules/IDE/components/FileNode';
6+
7+
8+
const Explorer = ({ id, canEdit, onPressClose }) => (
9+
<Sidebar title="Files" onPressClose={onPressClose}>
10+
<ConnectedFileNode id={id} canEdit={canEdit} onClickFile={() => onPressClose()} />
11+
</Sidebar>
12+
);
13+
14+
Explorer.propTypes = {
15+
id: PropTypes.number.isRequired,
16+
onPressClose: PropTypes.func,
17+
canEdit: PropTypes.bool
18+
};
19+
Explorer.defaultProps = {
20+
canEdit: false,
21+
onPressClose: () => {}
22+
};
23+
24+
export default Explorer;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import styled from 'styled-components';
4+
import { remSize, prop } from '../../theme';
5+
import Button from '../../common/Button';
6+
import IconButton from './IconButton';
7+
8+
const FloatingContainer = styled.div`
9+
position: fixed;
10+
right: ${remSize(16)};
11+
top: ${remSize(80)};
12+
13+
text-align: right;
14+
z-index: 3;
15+
16+
svg { width: ${remSize(32)}; };
17+
svg > path { fill: ${prop('Button.default.background')} !important };
18+
`;
19+
20+
const FloatingNav = ({ items }) => (
21+
<FloatingContainer>
22+
{ items.map(({ icon, onPress }) =>
23+
(
24+
<IconButton
25+
onClick={onPress}
26+
icon={icon}
27+
/>
28+
))}
29+
</FloatingContainer>
30+
);
31+
32+
FloatingNav.propTypes = {
33+
items: PropTypes.arrayOf(PropTypes.shape({
34+
icon: PropTypes.element,
35+
onPress: PropTypes.func
36+
}))
37+
};
38+
39+
FloatingNav.defaultProps = {
40+
items: []
41+
};
42+
43+
export default FloatingNav;

client/components/mobile/Header.jsx

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,22 @@ import styled from 'styled-components';
33
import PropTypes from 'prop-types';
44
import { prop, remSize } from '../../theme';
55

6-
const background = transparent => prop(transparent ? 'backgroundColor' : 'MobilePanel.default.background');
7-
const textColor = prop('primaryTextColor');
6+
7+
const background = ({ transparent, inverted }) => prop(transparent === true
8+
? 'backgroundColor'
9+
: `MobilePanel.default.${inverted === true ? 'foreground' : 'background'}`);
10+
11+
const textColor = ({ transparent, inverted }) => prop((transparent === false && inverted === true)
12+
? 'MobilePanel.default.background'
13+
: 'primaryTextColor');
814

915

1016
const HeaderDiv = styled.div`
11-
position: fixed;
17+
${props => props.fixed && 'position: fixed;'}
1218
width: 100%;
13-
background: ${props => background(props.transparent === true)};
19+
background: ${props => background(props)};
1420
color: ${textColor};
15-
padding: ${remSize(12)};
21+
padding: ${props => remSize(props.slim === true ? 2 : 12)};
1622
padding-left: ${remSize(16)};
1723
padding-right: ${remSize(16)};
1824
z-index: 1;
@@ -25,8 +31,10 @@ const HeaderDiv = styled.div`
2531
2632
svg {
2733
max-height: ${remSize(32)};
28-
padding: ${remSize(4)}
34+
padding: ${remSize(4)};
2935
}
36+
37+
& svg path { fill: ${textColor} !important; }
3038
`;
3139

3240
const IconContainer = styled.div`
@@ -48,9 +56,10 @@ const TitleContainer = styled.div`
4856
`;
4957

5058
const Header = ({
51-
title, subtitle, leftButton, children, transparent
59+
title, subtitle, leftButton, children,
60+
transparent, inverted, slim, fixed
5261
}) => (
53-
<HeaderDiv transparent={transparent}>
62+
<HeaderDiv transparent={transparent} slim={slim} inverted={inverted} fixed={fixed}>
5463
{leftButton}
5564
<TitleContainer padded={subtitle === null}>
5665
{title && <h2>{title}</h2>}
@@ -67,15 +76,21 @@ Header.propTypes = {
6776
subtitle: PropTypes.string,
6877
leftButton: PropTypes.element,
6978
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),
70-
transparent: PropTypes.bool
79+
transparent: PropTypes.bool,
80+
inverted: PropTypes.bool,
81+
slim: PropTypes.bool,
82+
fixed: PropTypes.bool,
7183
};
7284

7385
Header.defaultProps = {
7486
title: null,
7587
subtitle: null,
7688
leftButton: null,
7789
children: [],
78-
transparent: false
90+
transparent: false,
91+
inverted: false,
92+
slim: false,
93+
fixed: true
7994
};
8095

8196
export default Header;

client/components/mobile/IDEWrapper.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import React from 'react';
22
import styled from 'styled-components';
33
import { remSize } from '../../theme';
44

5+
// Applies padding to top and bottom so editor content is always visible
6+
57
export default styled.div`
68
z-index: 0;
79
margin-top: ${remSize(16)};
10+
.CodeMirror-sizer > * { padding-bottom: ${remSize(320)}; };
811
`;

client/components/mobile/Sidebar.jsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Link } from 'react-router';
4+
import styled from 'styled-components';
5+
import { remSize, prop, common } from '../../theme';
6+
import Header from './Header';
7+
import IconButton from './IconButton';
8+
import { ExitIcon } from '../../common/icons';
9+
10+
11+
const SidebarWrapper = styled.div`
12+
height: 100%;
13+
width: ${remSize(180)};
14+
15+
position: fixed;
16+
z-index: 2;
17+
left: 0;
18+
19+
background: white;
20+
box-shadow: 0 6px 6px 0 rgba(0,0,0,0.10);
21+
`;
22+
23+
const Sidebar = ({ title, onPressClose, children }) => (
24+
<SidebarWrapper>
25+
{title &&
26+
<Header slim title={title} fixed={false}>
27+
<IconButton onClick={onPressClose} icon={ExitIcon} aria-label="Return to ide view" />
28+
</Header>}
29+
{children}
30+
</SidebarWrapper>
31+
);
32+
33+
Sidebar.propTypes = {
34+
title: PropTypes.string,
35+
onPressClose: PropTypes.func,
36+
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),
37+
};
38+
39+
Sidebar.defaultProps = {
40+
title: null,
41+
children: [],
42+
onPressClose: () => {}
43+
};
44+
45+
46+
export default Sidebar;

0 commit comments

Comments
 (0)