Skip to content

Add Dropdown Menu to the mobile IDE View #1513

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ac0c519
:construction: create <Dropdown /> component
ghalestrilo Jul 21, 2020
b3e88aa
Merge branch 'develop' of https://github.com/processing/p5.js-web-edi…
ghalestrilo Jul 21, 2020
24e6b36
:bento: create <MoreIcon />
ghalestrilo Jul 21, 2020
ca88c4e
:construction: put an invisible <Dropdown /> on MobileIDEView
ghalestrilo Jul 21, 2020
91a766d
:construction: import dropdown list style from scss
ghalestrilo Jul 22, 2020
c58cdc2
:construction: add navigation elements to the dropdown menu
ghalestrilo Jul 22, 2020
371e4cc
:alembic: create <OverlayManager /> component
ghalestrilo Jul 22, 2020
9f8b41c
:sparkles: make dropdown menu open and close
ghalestrilo Jul 24, 2020
9bebf9f
:twisted_rightwards_arrows: merge from develop
ghalestrilo Jul 24, 2020
0a065cb
:broom: unhide sidebar
ghalestrilo Jul 24, 2020
f7d0631
:ok_hand: remove isRequired from consoleEvents
ghalestrilo Jul 24, 2020
77a40a9
:ok_hand: rename last menu option to 'Original Editor'
ghalestrilo Jul 24, 2020
4abdc65
:twisted_rightwards_arrows: merge from develop
ghalestrilo Jul 28, 2020
f5e901a
:ok_hand: add CodeIcon to icons.jsx
ghalestrilo Jul 28, 2020
d2dcc1f
:ok_hand: restore Console.jsx classes
ghalestrilo Jul 28, 2020
dd37c77
:ok_hand: remove eslint-disable-lines
ghalestrilo Jul 28, 2020
f9c0e80
:bug: restore package-lock.json
ghalestrilo Jul 28, 2020
b8bdfd9
Merge branch 'develop' into feature/mobile-header-dropdown-menu
ghalestrilo Jul 28, 2020
8339be1
:recycle: create useHideOnBlur hook
ghalestrilo Jul 29, 2020
8da6497
:recycle: create useAsModal HOC
ghalestrilo Jul 29, 2020
e430652
:recycle: make dropdown left/rightable
ghalestrilo Jul 29, 2020
7c2a624
:firetruck: restore devtools sidebar
ghalestrilo Jul 29, 2020
10ccc19
:bug: update mobile nav paths
ghalestrilo Jul 29, 2020
ea9a2f9
:recycle: make li into styled component
ghalestrilo Jul 29, 2020
8acd6ec
:ok_hand: move hoc to components folder
ghalestrilo Jul 30, 2020
8225807
:ok_hand: subst left/right props with align prop on <Dropdown />
ghalestrilo Jul 30, 2020
7272afe
Merge branch 'develop' into feature/mobile-header-dropdown-menu
catarak Jul 30, 2020
ab93a4c
:ok_hand: make dropdown list toggle on enter/click
ghalestrilo Jul 30, 2020
ed989ee
Merge branch 'develop' of https://github.com/processing/p5.js-web-edi…
ghalestrilo Jul 31, 2020
78d4fc4
:ok_hand: remove eslint disable lines
ghalestrilo Jul 31, 2020
e1fd49b
:bug: fix dropdown defaulting to open
ghalestrilo Aug 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions client/common/icons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
92 changes: 92 additions & 0 deletions client/components/Dropdown.jsx
Original file line number Diff line number Diff line change
@@ -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 && <Element aria-label={label} />;

const Dropdown = ({ items, align }) => (
<DropdownWrapper align={align} >
{/* className="nav__items-left" */}
{items && items.map(({ title, icon, href }) => (
<li key={`nav-${title && title.toLowerCase()}`}>
<Link to={href}>
{/* {MaybeIcon(icon, `Navigate to ${title}`)} */}
{title}
</Link>
</li>
))
}
</DropdownWrapper>
);

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;
27 changes: 27 additions & 0 deletions client/components/OverlayManager.jsx
Original file line number Diff line number Diff line change
@@ -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 = (
<React.Fragment>
{/* <div ref={setRef} >
{visible && <Dropdown items={headerNavOptions} />}
</div> */}
</React.Fragment>
);

return jsx && createPortal(jsx, document.body);
};


OverlayManager.propTypes = {
overlay: PropTypes.string,
hideOverlay: PropTypes.func.isRequired,
};

OverlayManager.defaultProps = { overlay: null };

export default OverlayManager;
2 changes: 2 additions & 0 deletions client/components/mobile/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
`;


Expand Down
10 changes: 10 additions & 0 deletions client/components/useAsModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { useModalBehavior } from '../utils/custom-hooks';

export default (component) => {
const [visible, trigger, setRef] = useModalBehavior();

const wrapper = () => <div ref={setRef}> {visible && component} </div>; // eslint-disable-line

return [trigger, wrapper];
};
5 changes: 5 additions & 0 deletions client/images/more.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion client/modules/App/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class App extends React.Component {
render() {
return (
<div className="app">
{this.state.isMounted && !window.devToolsExtension && getConfig('NODE_ENV') === 'development' && <DevTools />}
{/* FIXME: Remove false */}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming you want to remove this for this PR!

{false && this.state.isMounted && !window.devToolsExtension && getConfig('NODE_ENV') === 'development' && <DevTools />}
{this.props.children}
</div>
);
Expand Down
2 changes: 0 additions & 2 deletions client/modules/IDE/components/Console.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
56 changes: 36 additions & 20 deletions client/modules/IDE/pages/MobileIDEView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';
Expand All @@ -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);

Expand All @@ -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(<Dropdown align="right" items={headerNavOptions} />);

return (
<Screen fullscreen>
Expand All @@ -58,13 +76,17 @@ const MobileIDEView = (props) => {
<IconButton to="/mobile" icon={ExitIcon} aria-label="Return to original editor" />
}
>
<IconButton
to="/mobile/preferences"
onClick={() => setOverlay('preferences')}
icon={PreferencesIcon}
aria-label="Open preferences menu"
/>
<IconButton to="/mobile/preview" onClick={() => { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" />
<NavItem>
<IconButton
onClick={triggerNavDropdown}
icon={MoreIcon}
aria-label="Options"
/>
<NavDropDown />
</NavItem>
<li>
<IconButton to="/mobile/preview" onClick={() => { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" />
</li>
</Header>

<IDEWrapper>
Expand All @@ -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}
Expand All @@ -103,6 +123,7 @@ const MobileIDEView = (props) => {
provideController={setTmController}
/>
</IDEWrapper>

<Footer>
{ide.consoleIsExpanded && <Expander expanded><Console /></Expander>}
<ActionStrip />
Expand All @@ -111,7 +132,6 @@ const MobileIDEView = (props) => {
);
};


MobileIDEView.propTypes = {

preferences: PropTypes.shape({
Expand All @@ -130,7 +150,7 @@ MobileIDEView.propTypes = {
ide: PropTypes.shape({
isPlaying: PropTypes.bool.isRequired,
isAccessibleOutputPlaying: PropTypes.bool.isRequired,
consoleEvent: PropTypes.array,
consoleEvent: PropTypes.arrayOf(PropTypes.shape({})),
modalIsVisible: PropTypes.bool.isRequired,
sidebarIsExpanded: PropTypes.bool.isRequired,
consoleIsExpanded: PropTypes.bool.isRequired,
Expand All @@ -156,7 +176,7 @@ MobileIDEView.propTypes = {
}).isRequired,

editorAccessibility: PropTypes.shape({
lintMessages: PropTypes.array.isRequired,
lintMessages: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
}).isRequired,

project: PropTypes.shape({
Expand Down Expand Up @@ -193,10 +213,6 @@ MobileIDEView.propTypes = {

showEditorOptions: PropTypes.func.isRequired,

showKeyboardShortcutModal: PropTypes.func.isRequired,

setUnsavedChanges: PropTypes.func.isRequired,

startRefreshSketch: PropTypes.func.isRequired,

stopSketch: PropTypes.func.isRequired,
Expand Down
5 changes: 2 additions & 3 deletions client/modules/Mobile/MobileSketchView.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect, useSelector, useDispatch } from 'react-redux';
import { useSelector, useDispatch } from 'react-redux';
import styled from 'styled-components';
import Header from '../../components/mobile/Header';
import IconButton from '../../components/mobile/IconButton';
Expand All @@ -25,7 +24,7 @@ const Content = styled.div`
margin-top: ${remSize(68)};
`;

const MobileSketchView = (props) => {
const MobileSketchView = () => {
const { files, ide, preferences } = useSelector(state => state);

const htmlFile = useSelector(state => getHTMLFile(state.files));
Expand Down
15 changes: 14 additions & 1 deletion client/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export const grays = {
};

export const common = {
baseFontSize: 12
baseFontSize: 12,
shadowColor: 'rgba(0, 0, 0, 0.16)'
};

export const remSize = size => `${size / common.baseFontSize}rem`;
Expand Down Expand Up @@ -97,6 +98,10 @@ export default {
border: grays.middleLight,
},
},
Modal: {
background: grays.light,
border: grays.middleLight
},
Separator: grays.middleLight,
},
[Theme.dark]: {
Expand Down Expand Up @@ -138,6 +143,10 @@ export default {
border: grays.middleDark,
},
},
Modal: {
background: grays.dark,
border: grays.middleDark
},
Separator: grays.middleDark,
},
[Theme.contrast]: {
Expand Down Expand Up @@ -179,6 +188,10 @@ export default {
border: grays.middleDark,
},
},
Modal: {
background: grays.dark,
border: grays.middleDark
},
Separator: grays.middleDark,
},
};
Loading