diff --git a/client/components/Dropdown.jsx b/client/components/Dropdown.jsx
index 48bed0cb24..885cdc1890 100644
--- a/client/components/Dropdown.jsx
+++ b/client/components/Dropdown.jsx
@@ -36,9 +36,7 @@ const DropdownWrapper = styled.ul`
background-color: ${prop('Button.hover.background')};
color: ${prop('Button.hover.foreground')};
- & button, & a {
- color: ${prop('Button.hover.foreground')};
- }
+ * { color: ${prop('Button.hover.foreground')}; }
}
li {
@@ -48,12 +46,21 @@ const DropdownWrapper = styled.ul`
align-items: center;
& button,
+ & button span,
& a {
+ padding: ${remSize(8)} ${remSize(16)};
+ }
+
+ * {
+ text-align: left;
+ justify-content: left;
+
color: ${prop('primaryTextColor')};
width: 100%;
- text-align: left;
- padding: ${remSize(8)} ${remSize(16)};
+ justify-content: flex-start;
}
+
+ & button span { padding: 0px }
}
`;
@@ -63,18 +70,22 @@ const DropdownWrapper = styled.ul`
const Dropdown = ({ items, align }) => (
{/* className="nav__items-left" */}
- {items && items.map(({ title, icon, href }) => (
+ {items && items.map(({
+ title, icon, href, action
+ }) => (
-
- {/* {MaybeIcon(icon, `Navigate to ${title}`)} */}
- {title}
-
+ {/* {MaybeIcon(icon, `Navigate to ${title}`)} */}
+ {href
+ ? {title}
+ : action()}>{title}}
+
))
}
);
+
Dropdown.propTypes = {
align: PropTypes.oneOf(['left', 'right']),
items: PropTypes.arrayOf(PropTypes.shape({
diff --git a/client/components/mobile/IconButton.jsx b/client/components/mobile/IconButton.jsx
index 08f0531132..7085f8a148 100644
--- a/client/components/mobile/IconButton.jsx
+++ b/client/components/mobile/IconButton.jsx
@@ -17,7 +17,7 @@ const IconButton = (props) => {
const Icon = icon;
return (}
+ iconBefore={icon && }
kind={Button.kinds.inline}
focusable="false"
{...otherProps}
@@ -25,7 +25,11 @@ const IconButton = (props) => {
};
IconButton.propTypes = {
- icon: PropTypes.func.isRequired
+ icon: PropTypes.func
+};
+
+IconButton.defaultProps = {
+ icon: null
};
export default IconButton;
diff --git a/client/modules/IDE/pages/MobileIDEView.jsx b/client/modules/IDE/pages/MobileIDEView.jsx
index a1ab0ea729..7826dca25a 100644
--- a/client/modules/IDE/pages/MobileIDEView.jsx
+++ b/client/modules/IDE/pages/MobileIDEView.jsx
@@ -20,7 +20,7 @@ import { getHTMLFile } from '../reducers/files';
// Local Imports
import Editor from '../components/Editor';
-import { PlayIcon, MoreIcon, CircleFolderIcon } from '../../../common/icons';
+import { PlayIcon, MoreIcon } from '../../../common/icons';
import IconButton from '../../../components/mobile/IconButton';
import Header from '../../../components/mobile/Header';
@@ -63,18 +63,20 @@ const NavItem = styled.li`
position: relative;
`;
-const getNavOptions = (username = undefined) =>
+const getNavOptions = (username = undefined, logoutUser = () => {}) =>
(username
? [
{ icon: PreferencesIcon, title: 'Preferences', href: '/mobile/preferences', },
{ icon: PreferencesIcon, title: 'My Stuff', href: `/mobile/${username}/sketches` },
{ icon: PreferencesIcon, title: 'Examples', href: '/mobile/p5/sketches' },
{ icon: PreferencesIcon, title: 'Original Editor', href: '/', },
+ { icon: PreferencesIcon, title: 'Logout', action: logoutUser, },
]
: [
{ icon: PreferencesIcon, title: 'Preferences', href: '/mobile/preferences', },
{ icon: PreferencesIcon, title: 'Examples', href: '/mobile/p5/sketches' },
{ icon: PreferencesIcon, title: 'Original Editor', href: '/', },
+ { icon: PreferencesIcon, title: 'Login', href: '/login', },
]
);
@@ -82,7 +84,7 @@ const MobileIDEView = (props) => {
const {
preferences, ide, editorAccessibility, project, updateLintMessage, clearLintMessage,
selectedFile, updateFileContent, files, user, params,
- closeEditorOptions, showEditorOptions,
+ closeEditorOptions, showEditorOptions, logoutUser,
startRefreshSketch, stopSketch, expandSidebar, collapseSidebar, clearConsole, console,
showRuntimeErrorWarning, hideRuntimeErrorWarning, startSketch, getProject, clearPersistedState, setUnsavedChanges
} = props;
@@ -110,7 +112,7 @@ const MobileIDEView = (props) => {
// Screen Modals
const [toggleNavDropdown, NavDropDown] = useAsModal();
@@ -294,6 +296,8 @@ MobileIDEView.propTypes = {
username: PropTypes.string,
}).isRequired,
+ logoutUser: PropTypes.func.isRequired,
+
setUnsavedChanges: PropTypes.func.isRequired,
getProject: PropTypes.func.isRequired,
clearPersistedState: PropTypes.func.isRequired,
diff --git a/client/modules/User/components/ResponsiveForm.jsx b/client/modules/User/components/ResponsiveForm.jsx
new file mode 100644
index 0000000000..a63cfb020a
--- /dev/null
+++ b/client/modules/User/components/ResponsiveForm.jsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import styled from 'styled-components';
+import PropTypes from 'prop-types';
+import { remSize } from '../../../theme';
+
+
+const ResponsiveFormWrapper = styled.div`
+ .form-container__content {
+ width: unset !important;
+ padding-top: ${remSize(16)};
+ padding-bottom: ${remSize(64)};
+ }
+
+ .form__input {
+ min-width: unset;
+ padding: 0px ${remSize(12)};
+ height: ${remSize(28)};
+ }
+ .form-container__title { margin-bottom: ${remSize(14)}}
+ p.form__field { margin-top: 0px !important; }
+ label.form__label { margin-top: ${remSize(8)} !important; }
+
+ .form-error { width: 100% }
+
+ .nav__items-right:last-child { display: none }
+
+ .form-container {
+ height: 100%
+ }
+
+ .nav__dropdown {
+ right: 0 !important;
+ left: unset !important;
+ }
+
+ .form-container__stack {
+ svg {
+ width: ${remSize(12)};
+ height: ${remSize(12)}
+ }
+ a { padding: 0px }
+ }
+`;
+
+const ResponsiveForm = props =>
+ (props.mobile === true
+ ? (
+
+ {props.children}
+
+
+ )
+ : props.children);
+
+ResponsiveForm.propTypes = {
+ mobile: PropTypes.bool,
+ children: PropTypes.oneOfType([PropTypes.node, PropTypes.array]),
+};
+ResponsiveForm.defaultProps = {
+ mobile: false,
+ children: []
+};
+
+export default ResponsiveForm;
diff --git a/client/modules/User/pages/LoginView.jsx b/client/modules/User/pages/LoginView.jsx
index 20b48b17f0..cdd2b97f08 100644
--- a/client/modules/User/pages/LoginView.jsx
+++ b/client/modules/User/pages/LoginView.jsx
@@ -10,6 +10,7 @@ import LoginForm from '../components/LoginForm';
import { validateLogin } from '../../../utils/reduxFormUtils';
import SocialAuthButton from '../components/SocialAuthButton';
import Nav from '../../../components/Nav';
+import ResponsiveForm from '../components/ResponsiveForm';
class LoginView extends React.Component {
constructor(props) {
@@ -27,36 +28,40 @@ class LoginView extends React.Component {
}
render() {
+ const isMobile = () => (window.innerWidth < 770);
if (this.props.user.authenticated) {
this.gotoHomePage();
return null;
}
+ // TODO: mobile currently forced to true
return (
-
-
-
-
- {this.props.t('LoginView.Title')}
-
-
-
{this.props.t('LoginView.Login')}
-
-
{this.props.t('LoginView.LoginOr')}
-
-
-
+
+
+
+
+
+ {this.props.t('LoginView.Title')}
+
+
+
{this.props.t('LoginView.Login')}
+
+
{this.props.t('LoginView.LoginOr')}
+
+
+
+
+
+ {this.props.t('LoginView.DontHaveAccount')}
+ {this.props.t('LoginView.SignUp')}
+
+
+ {this.props.t('LoginView.ForgotPassword')}
+ {this.props.t('LoginView.ResetPassword')}
+
-
- {this.props.t('LoginView.DontHaveAccount')}
- {this.props.t('LoginView.SignUp')}
-
-
- {this.props.t('LoginView.ForgotPassword')}
- {this.props.t('LoginView.ResetPassword')}
-
-
-
-
+
+
+
);
}
}
@@ -79,13 +84,15 @@ LoginView.propTypes = {
user: PropTypes.shape({
authenticated: PropTypes.bool
}),
- t: PropTypes.func.isRequired
+ t: PropTypes.func.isRequired,
+ mobile: PropTypes.bool
};
LoginView.defaultProps = {
user: {
authenticated: false
- }
+ },
+ mobile: false
};
export default withTranslation()(reduxForm({
diff --git a/client/modules/User/pages/SignupView.jsx b/client/modules/User/pages/SignupView.jsx
index b646a40584..4cebe88c18 100644
--- a/client/modules/User/pages/SignupView.jsx
+++ b/client/modules/User/pages/SignupView.jsx
@@ -11,6 +11,9 @@ import apiClient from '../../../utils/apiClient';
import { validateSignup } from '../../../utils/reduxFormUtils';
import SocialAuthButton from '../components/SocialAuthButton';
import Nav from '../../../components/Nav';
+import ResponsiveForm from '../components/ResponsiveForm';
+
+const isMobile = () => (window.innerWidth < 770);
class SignupView extends React.Component {
gotoHomePage = () => {
@@ -23,27 +26,29 @@ class SignupView extends React.Component {
return null;
}
return (
-
-
-
-
- {this.props.t('SignupView.Title')}
-
-
-
{this.props.t('SignupView.Description')}
-
-
{this.props.t('SignupView.Or')}
-
-
-
+
+
+
+
+
+ {this.props.t('SignupView.Title')}
+
+
+
{this.props.t('SignupView.Description')}
+
+
{this.props.t('SignupView.Or')}
+
+
+
+
+
+ {this.props.t('SignupView.AlreadyHave')}
+ {this.props.t('SignupView.Login')}
+
-
- {this.props.t('SignupView.AlreadyHave')}
- {this.props.t('SignupView.Login')}
-
-
-
-
+
+
+
);
}
}
@@ -110,13 +115,15 @@ SignupView.propTypes = {
user: PropTypes.shape({
authenticated: PropTypes.bool
}),
- t: PropTypes.func.isRequired
+ t: PropTypes.func.isRequired,
+ mobile: PropTypes.bool
};
SignupView.defaultProps = {
user: {
authenticated: false
- }
+ },
+ mobile: false
};
export default withTranslation()(reduxForm({