diff --git a/client/components/Dropdown.jsx b/client/components/Dropdown.jsx index 48bed0cb..885cdc18 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 { - color: ${prop('primaryTextColor')}; - width: 100%; - text-align: left; padding: ${remSize(8)} ${remSize(16)}; } + + * { + text-align: left; + justify-content: left; + + color: ${prop('primaryTextColor')}; + width: 100%; + 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 08f05311..7085f8a1 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 a1ab0ea7..7826dca2 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 00000000..a63cfb02 --- /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 20b48b17..cdd2b97f 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 ( -
    -
    + + + ); } } @@ -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 b646a405..4cebe88c 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 ( -
    -
    + + + ); } } @@ -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({