diff --git a/client/common/icons.jsx b/client/common/icons.jsx index 624f9f31..215083a6 100644 --- a/client/common/icons.jsx +++ b/client/common/icons.jsx @@ -12,6 +12,7 @@ import Exit from '../images/exit.svg'; import DropdownArrow from '../images/down-filled-triangle.svg'; import Preferences from '../images/preferences.svg'; import Play from '../images/triangle-arrow-right.svg'; +import More from '../images/more.svg'; import Code from '../images/code.svg'; import Terminal from '../images/terminal.svg'; @@ -77,4 +78,6 @@ export const ExitIcon = withLabel(Exit); export const DropdownArrowIcon = withLabel(DropdownArrow); export const PreferencesIcon = withLabel(Preferences); export const PlayIcon = withLabel(Play); +export const MoreIcon = withLabel(More); export const TerminalIcon = withLabel(Terminal); +export const CodeIcon = withLabel(Code); diff --git a/client/components/Dropdown.jsx b/client/components/Dropdown.jsx new file mode 100644 index 00000000..bd2169b8 --- /dev/null +++ b/client/components/Dropdown.jsx @@ -0,0 +1,92 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link } from 'react-router'; +import styled from 'styled-components'; +import { remSize, prop, common } from '../theme'; +import IconButton from './mobile/IconButton'; +import Button from '../common/Button'; + +const DropdownWrapper = styled.ul` + background-color: ${prop('Modal.background')}; + border: 1px solid ${prop('Modal.border')}; + box-shadow: 0 0 18px 0 ${prop('shadowColor')}; + color: ${prop('primaryTextColor')}; + + position: absolute; + right: ${props => (props.right ? 0 : 'initial')}; + left: ${props => (props.left ? 0 : 'initial')}; + + ${props => (props.align === 'right' && 'right: 0;')} + ${props => (props.align === 'left' && 'left: 0;')} + + + text-align: left; + width: ${remSize(180)}; + display: flex; + flex-direction: column; + height: auto; + z-index: 9999; + border-radius: ${remSize(6)}; + + & li:first-child { border-radius: ${remSize(5)} ${remSize(5)} 0 0; } + & li:last-child { border-radius: 0 0 ${remSize(5)} ${remSize(5)}; } + + & li:hover { + + background-color: ${prop('Button.hover.background')}; + color: ${prop('Button.hover.foreground')}; + + & button, & a { + color: ${prop('Button.hover.foreground')}; + } + } + + li { + height: ${remSize(36)}; + cursor: pointer; + display: flex; + align-items: center; + + & button, + & a { + color: ${prop('primaryTextColor')}; + width: 100%; + text-align: left; + padding: ${remSize(8)} ${remSize(16)}; + } + } +`; + +// TODO: Add Icon to the left of the items in the menu +// const MaybeIcon = (Element, label) => Element && ; + +const Dropdown = ({ items, align }) => ( + + {/* className="nav__items-left" */} + {items && items.map(({ title, icon, href }) => ( +
  • + + {/* {MaybeIcon(icon, `Navigate to ${title}`)} */} + {title} + +
  • + )) + } +
    +); + +Dropdown.propTypes = { + align: PropTypes.oneOf(['left', 'right']), + items: PropTypes.arrayOf(PropTypes.shape({ + action: PropTypes.func, + icon: PropTypes.func, + href: PropTypes.string + })), +}; + +Dropdown.defaultProps = { + items: [], + align: null +}; + +export default Dropdown; diff --git a/client/components/OverlayManager.jsx b/client/components/OverlayManager.jsx new file mode 100644 index 00000000..1b3b040c --- /dev/null +++ b/client/components/OverlayManager.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { createPortal } from 'react-dom'; + +const OverlayManager = ({ overlay, hideOverlay }) => { + // const [visible, trigger, setRef] = useModalBehavior(); + + const jsx = ( + + {/*
    + {visible && } +
    */} +
    + ); + + return jsx && createPortal(jsx, document.body); +}; + + +OverlayManager.propTypes = { + overlay: PropTypes.string, + hideOverlay: PropTypes.func.isRequired, +}; + +OverlayManager.defaultProps = { overlay: null }; + +export default OverlayManager; diff --git a/client/components/mobile/Header.jsx b/client/components/mobile/Header.jsx index cf727b7c..ded0b3be 100644 --- a/client/components/mobile/Header.jsx +++ b/client/components/mobile/Header.jsx @@ -31,7 +31,9 @@ const HeaderDiv = styled.div` const IconContainer = styled.div` margin-left: ${props => (props.leftButton ? remSize(32) : remSize(4))}; + list-style: none; display: flex; + flex-direction: horizontal; `; diff --git a/client/components/useAsModal.jsx b/client/components/useAsModal.jsx new file mode 100644 index 00000000..1afa0d30 --- /dev/null +++ b/client/components/useAsModal.jsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { useModalBehavior } from '../utils/custom-hooks'; + +export default (component) => { + const [visible, trigger, setRef] = useModalBehavior(); + + const wrapper = () =>
    {visible && component}
    ; // eslint-disable-line + + return [trigger, wrapper]; +}; diff --git a/client/images/more.svg b/client/images/more.svg new file mode 100644 index 00000000..ee41de95 --- /dev/null +++ b/client/images/more.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/modules/IDE/components/Console.jsx b/client/modules/IDE/components/Console.jsx index ddb6d55e..749caaaa 100644 --- a/client/modules/IDE/components/Console.jsx +++ b/client/modules/IDE/components/Console.jsx @@ -88,8 +88,6 @@ const Console = () => { const cm = useRef({}); - useDidUpdate(() => { cm.current.scrollTop = cm.current.scrollHeight; }); - const consoleClass = classNames({ 'preview-console': true, 'preview-console--collapsed': !isExpanded diff --git a/client/modules/IDE/pages/MobileIDEView.jsx b/client/modules/IDE/pages/MobileIDEView.jsx index 43851092..badeda6b 100644 --- a/client/modules/IDE/pages/MobileIDEView.jsx +++ b/client/modules/IDE/pages/MobileIDEView.jsx @@ -7,6 +7,7 @@ import styled from 'styled-components'; // Imports to be Refactored import { bindActionCreators } from 'redux'; + import * as FileActions from '../actions/files'; import * as IDEActions from '../actions/ide'; import * as ProjectActions from '../actions/project'; @@ -19,7 +20,7 @@ import { getHTMLFile } from '../reducers/files'; // Local Imports import Editor from '../components/Editor'; -import { PreferencesIcon, PlayIcon, ExitIcon } from '../../../common/icons'; +import { PlayIcon, ExitIcon, MoreIcon } from '../../../common/icons'; import IconButton from '../../../components/mobile/IconButton'; import Header from '../../../components/mobile/Header'; @@ -28,7 +29,11 @@ import Footer from '../../../components/mobile/Footer'; import IDEWrapper from '../../../components/mobile/IDEWrapper'; import Console from '../components/Console'; import { remSize } from '../../../theme'; +// import OverlayManager from '../../../components/OverlayManager'; import ActionStrip from '../../../components/mobile/ActionStrip'; +import useAsModal from '../../../components/useAsModal'; +import { PreferencesIcon } from '../../../common/icons'; +import Dropdown from '../../../components/Dropdown'; const isUserOwner = ({ project, user }) => (project.owner && project.owner.id === user.id); @@ -37,17 +42,30 @@ const Expander = styled.div` height: ${props => (props.expanded ? remSize(160) : remSize(27))}; `; +const NavItem = styled.li` + position: relative; +`; + +const headerNavOptions = [ + { icon: PreferencesIcon, title: 'Preferences', href: '/mobile/preferences', }, + { icon: PreferencesIcon, title: 'Examples', href: '/mobile/examples' }, + { icon: PreferencesIcon, title: 'Original Editor', href: '/', }, +]; + + const MobileIDEView = (props) => { const { preferences, ide, editorAccessibility, project, updateLintMessage, clearLintMessage, selectedFile, updateFileContent, files, - closeEditorOptions, showEditorOptions, showKeyboardShortcutModal, setUnsavedChanges, + closeEditorOptions, showEditorOptions, startRefreshSketch, stopSketch, expandSidebar, collapseSidebar, clearConsole, console, showRuntimeErrorWarning, hideRuntimeErrorWarning, startSketch } = props; const [tmController, setTmController] = useState(null); // eslint-disable-line - const [overlay, setOverlay] = useState(null); // eslint-disable-line + + + const [triggerNavDropdown, NavDropDown] = useAsModal(); return ( @@ -58,13 +76,17 @@ const MobileIDEView = (props) => { } > - setOverlay('preferences')} - icon={PreferencesIcon} - aria-label="Open preferences menu" - /> - { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" /> + + + + +
  • + { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" /> +
  • @@ -82,9 +104,7 @@ const MobileIDEView = (props) => { editorOptionsVisible={ide.editorOptionsVisible} showEditorOptions={showEditorOptions} closeEditorOptions={closeEditorOptions} - showKeyboardShortcutModal={showKeyboardShortcutModal} - setUnsavedChanges={setUnsavedChanges} - isPlaying={ide.isPlaying} + showKeyboard={ide.isPlaying} theme={preferences.theme} startRefreshSketch={startRefreshSketch} stopSketch={stopSketch} @@ -103,6 +123,7 @@ const MobileIDEView = (props) => { provideController={setTmController} /> +