Skip to content

Commit 69bd6cb

Browse files
authored
Merge pull request #1472 from ghalestrilo/feature/mobile-settings-screen
Mobile Preferences Screen Prototype
2 parents ff658c7 + 88ebe9e commit 69bd6cb

File tree

9 files changed

+387
-46
lines changed

9 files changed

+387
-46
lines changed

Diff for: client/components/mobile/Header.jsx

+53-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import React from 'react';
22
import styled from 'styled-components';
3+
import PropTypes from 'prop-types';
34
import { prop, remSize } from '../../theme';
45

56
const background = prop('MobilePanel.default.background');
67
const textColor = prop('primaryTextColor');
78

8-
const Header = styled.div`
9+
10+
const HeaderDiv = styled.div`
911
position: fixed;
1012
width: 100%;
11-
background: ${background};
13+
background: ${props => (props.transparent ? 'transparent' : background)};
1214
color: ${textColor};
1315
padding: ${remSize(12)};
1416
padding-left: ${remSize(16)};
@@ -23,8 +25,56 @@ const Header = styled.div`
2325
2426
// TODO:
2527
svg {
26-
height: 2rem;
28+
max-height: ${remSize(32)};
29+
padding: ${remSize(4)}
2730
}
2831
`;
2932

33+
const IconContainer = styled.div`
34+
margin-left: ${props => (props.leftButton ? remSize(32) : remSize(4))};
35+
display: flex;
36+
`;
37+
38+
39+
const TitleContainer = styled.div`
40+
margin-left: ${remSize(4)};
41+
margin-right: auto;
42+
43+
${props => props.padded && `h2{
44+
padding-top: ${remSize(10)};
45+
padding-bottom: ${remSize(10)};
46+
}`}
47+
`;
48+
49+
const Header = ({
50+
title, subtitle, leftButton, children, transparent
51+
}) => (
52+
<HeaderDiv transparent={transparent}>
53+
{leftButton}
54+
<TitleContainer padded={subtitle === null}>
55+
{title && <h2>{title}</h2>}
56+
{subtitle && <h3>{subtitle}</h3>}
57+
</TitleContainer>
58+
<IconContainer>
59+
{children}
60+
</IconContainer>
61+
</HeaderDiv>
62+
);
63+
64+
Header.propTypes = {
65+
title: PropTypes.string,
66+
subtitle: PropTypes.string,
67+
leftButton: PropTypes.element,
68+
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),
69+
transparent: PropTypes.bool
70+
};
71+
72+
Header.defaultProps = {
73+
title: null,
74+
subtitle: null,
75+
leftButton: null,
76+
children: [],
77+
transparent: false
78+
};
79+
3080
export default Header;

Diff for: client/components/mobile/IconButton.jsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import styled from 'styled-components';
44
import Button from '../../common/Button';
5+
import { remSize } from '../../theme';
56

67
const ButtonWrapper = styled(Button)`
7-
width: 3rem;
8+
width: ${remSize(48)};
89
> svg {
910
width: 100%;
1011
height: 100%;

Diff for: client/components/mobile/MobileScreen.jsx

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33

4-
const Screen = ({ children }) => (
5-
<div className="fullscreen-preview">
4+
const Screen = ({ children, fullscreen }) => (
5+
<div className={fullscreen && 'fullscreen-preview'}>
66
{children}
77
</div>
88
);
9+
10+
Screen.defaultProps = {
11+
fullscreen: false
12+
};
13+
914
Screen.propTypes = {
10-
children: PropTypes.node.isRequired
15+
children: PropTypes.node.isRequired,
16+
fullscreen: PropTypes.bool
1117
};
1218

1319
export default Screen;

Diff for: client/components/mobile/PreferencePicker.jsx

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import styled from 'styled-components';
4+
import { prop, remSize } from '../../theme';
5+
6+
7+
const PreferenceTitle = styled.h4.attrs(props => ({ ...props, className: 'preference__title' }))`
8+
color: ${prop('primaryTextColor')};
9+
`;
10+
11+
const Preference = styled.div.attrs(props => ({ ...props, className: 'preference' }))`
12+
flex-wrap: nowrap !important;
13+
align-items: baseline !important;
14+
justify-items: space-between;
15+
`;
16+
17+
const OptionLabel = styled.label.attrs({ className: 'preference__option' })`
18+
font-size: ${remSize(14)} !important;
19+
`;
20+
21+
const PreferencePicker = ({
22+
title, value, onSelect, options,
23+
}) => (
24+
<Preference>
25+
<PreferenceTitle>{title}</PreferenceTitle>
26+
<div className="preference__options">
27+
{options.map(option => (
28+
<React.Fragment key={`${option.name}-${option.id}`} >
29+
<input
30+
type="radio"
31+
onChange={() => onSelect(option.value)}
32+
aria-label={option.ariaLabel}
33+
name={option.name}
34+
key={`${option.name}-${option.id}-input`}
35+
id={option.id}
36+
className="preference__radio-button"
37+
value={option.value}
38+
checked={value === option.value}
39+
/>
40+
<OptionLabel
41+
key={`${option.name}-${option.id}-label`}
42+
htmlFor={option.id}
43+
>
44+
{option.label}
45+
</OptionLabel>
46+
</React.Fragment>))}
47+
</div>
48+
</Preference>
49+
);
50+
51+
PreferencePicker.defaultProps = {
52+
options: []
53+
};
54+
55+
PreferencePicker.propTypes = {
56+
title: PropTypes.string.isRequired,
57+
value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]).isRequired,
58+
options: PropTypes.arrayOf(PropTypes.shape({
59+
id: PropTypes.string,
60+
name: PropTypes.string,
61+
label: PropTypes.string,
62+
ariaLabel: PropTypes.string,
63+
})),
64+
onSelect: PropTypes.func.isRequired,
65+
};
66+
67+
export default PreferencePicker;

Diff for: client/modules/IDE/pages/IDEViewMobile.jsx renamed to client/modules/IDE/pages/MobileIDEView.jsx

+18-27
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3-
import styled from 'styled-components';
4-
import { Link } from 'react-router';
53
import { connect } from 'react-redux';
64
import { withRouter } from 'react-router';
75
import { useState } from 'react';
@@ -27,16 +25,10 @@ import Header from '../../../components/mobile/Header';
2725
import Screen from '../../../components/mobile/MobileScreen';
2826
import Footer from '../../../components/mobile/Footer';
2927
import IDEWrapper from '../../../components/mobile/IDEWrapper';
30-
import { remSize } from '../../../theme';
31-
32-
const IconContainer = styled.div`
33-
margin-left: ${remSize(32)};
34-
display: flex;
35-
`;
3628

3729
const isUserOwner = ({ project, user }) => (project.owner && project.owner.id === user.id);
3830

39-
const IDEViewMobile = (props) => {
31+
const MobileIDEView = (props) => {
4032
const {
4133
preferences, ide, editorAccessibility, project, updateLintMessage, clearLintMessage,
4234
selectedFile, updateFileContent, files,
@@ -49,22 +41,21 @@ const IDEViewMobile = (props) => {
4941
const [overlay, setOverlay] = useState(null); // eslint-disable-line
5042

5143
return (
52-
<Screen>
53-
<Header>
54-
<IconButton to="/mobile" icon={ExitIcon} aria-label="Return to original editor" />
55-
<div style={{ marginLeft: '1rem' }}>
56-
<h2>{project.name}</h2>
57-
<h3>{selectedFile.name}</h3>
58-
</div>
59-
60-
<IconContainer>
61-
<IconButton
62-
onClick={() => setOverlay('preferences')}
63-
icon={PreferencesIcon}
64-
aria-label="Open preferences menu"
65-
/>
66-
<IconButton to="/mobile/preview" onClick={() => { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" />
67-
</IconContainer>
44+
<Screen fullscreen>
45+
<Header
46+
title={project.name}
47+
subtitle={selectedFile.name}
48+
leftButton={
49+
<IconButton to="/mobile" icon={ExitIcon} aria-label="Return to original editor" />
50+
}
51+
>
52+
<IconButton
53+
to="/mobile/preferences"
54+
onClick={() => setOverlay('preferences')}
55+
icon={PreferencesIcon}
56+
aria-label="Open preferences menu"
57+
/>
58+
<IconButton to="/mobile/preview" onClick={() => { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" />
6859
</Header>
6960

7061
<IDEWrapper>
@@ -109,7 +100,7 @@ const IDEViewMobile = (props) => {
109100
};
110101

111102

112-
IDEViewMobile.propTypes = {
103+
MobileIDEView.propTypes = {
113104

114105
preferences: PropTypes.shape({
115106
fontSize: PropTypes.number.isRequired,
@@ -256,4 +247,4 @@ function mapDispatchToProps(dispatch) {
256247
}
257248

258249

259-
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(IDEViewMobile));
250+
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MobileIDEView));

0 commit comments

Comments
 (0)