From 0e973068a5645fed044cb05d6c89ee81abdc16f4 Mon Sep 17 00:00:00 2001 From: Christopher Willis-Ford <7019101+cwillisf@users.noreply.github.com> Date: Wed, 2 Dec 2020 13:34:40 -0800 Subject: [PATCH] allow 'About' button to open a menu If `onClickAbout` is a callback, or is not provided, then behavior is the same as it was before this change. If the value is an array of objects with `title` and `onClick` properties, the "About" button will now open a menu with those items. TODO: support `FormattedMessage` for the menu item titles. --- src/components/gui/gui.jsx | 1 - src/components/menu-bar/menu-bar.jsx | 71 +++++++++++++++++++++++++++- src/reducers/menus.js | 8 ++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index f5c7e504c..518198c1c 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -395,7 +395,6 @@ GUIComponent.propTypes = { onActivateCostumesTab: PropTypes.func, onActivateSoundsTab: PropTypes.func, onActivateTab: PropTypes.func, - onClickAbout: PropTypes.func, onClickAccountNav: PropTypes.func, onClickLogo: PropTypes.func, onCloseAccountNav: PropTypes.func, diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx index 354e5c06d..126f0d460 100644 --- a/src/components/menu-bar/menu-bar.jsx +++ b/src/components/menu-bar/menu-bar.jsx @@ -41,6 +41,9 @@ import { saveProjectAsCopy } from '../../reducers/project-state'; import { + openAboutMenu, + closeAboutMenu, + aboutMenuOpen, openAccountMenu, closeAccountMenu, accountMenuOpen, @@ -282,6 +285,56 @@ class MenuBar extends React.Component { } } } + buildAboutMenu (onClickAbout) { + if (!onClickAbout) { + // hide the button + return null; + } + if (typeof onClickAbout === 'function') { + // make a button which calls a function + return <AboutButton onClick={onClickAbout} />; + } + // assume it's an array of objects + // each item must have a 'title' FormattedMessage and a 'handleClick' function + // generate a menu with items for each object in the array + return ( + <div + className={classNames(styles.menuBarItem, styles.hoverable, { + [styles.active]: this.props.aboutMenuOpen + })} + onMouseUp={this.props.onRequestOpenAbout} + > + <img + className={styles.aboutIcon} + src={aboutIcon} + /> + <MenuBarMenu + className={classNames(styles.menuBarMenu)} + open={this.props.aboutMenuOpen} + place={this.props.isRtl ? 'right' : 'left'} + onRequestClose={this.props.onRequestCloseAbout} + > + { + onClickAbout.map(itemProps => ( + <MenuItem + key={itemProps.title} + isRtl={this.props.isRtl} + onClick={this.wrapAboutMenuCallback(itemProps.onClick)} + > + {itemProps.title} + </MenuItem> + )) + } + </MenuBarMenu> + </div> + ); + } + wrapAboutMenuCallback (callback) { + return () => { + callback(); + this.props.onRequestCloseAbout(); + }; + } render () { const saveNowMessage = ( <FormattedMessage @@ -325,7 +378,7 @@ class MenuBar extends React.Component { </Button> ); // Show the About button only if we have a handler for it (like in the desktop app) - const aboutButton = this.props.onClickAbout ? <AboutButton onClick={this.props.onClickAbout} /> : null; + const aboutButton = this.buildAboutMenu(this.props.onClickAbout); return ( <Box className={classNames( @@ -701,6 +754,7 @@ class MenuBar extends React.Component { } MenuBar.propTypes = { + aboutMenuOpen: PropTypes.bool, accountMenuOpen: PropTypes.bool, authorId: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), authorThumbnailUrl: PropTypes.string, @@ -728,7 +782,15 @@ MenuBar.propTypes = { locale: PropTypes.string.isRequired, loginMenuOpen: PropTypes.bool, logo: PropTypes.string, - onClickAbout: PropTypes.func, + onClickAbout: PropTypes.oneOfType([ + PropTypes.func, // button mode: call this callback when the About button is clicked + PropTypes.arrayOf( // menu mode: list of items in the About menu + PropTypes.shape({ + title: PropTypes.string, // text for the menu item + onClick: PropTypes.func // call this callback when the menu item is clicked + }) + ) + ]), onClickAccount: PropTypes.func, onClickEdit: PropTypes.func, onClickFile: PropTypes.func, @@ -743,6 +805,8 @@ MenuBar.propTypes = { onOpenRegistration: PropTypes.func, onOpenTipLibrary: PropTypes.func, onProjectTelemetryEvent: PropTypes.func, + onRequestOpenAbout: PropTypes.func, + onRequestCloseAbout: PropTypes.func, onRequestCloseAccount: PropTypes.func, onRequestCloseEdit: PropTypes.func, onRequestCloseFile: PropTypes.func, @@ -771,6 +835,7 @@ const mapStateToProps = (state, ownProps) => { const loadingState = state.scratchGui.projectState.loadingState; const user = state.session && state.session.session && state.session.session.user; return { + aboutMenuOpen: aboutMenuOpen(state), accountMenuOpen: accountMenuOpen(state), fileMenuOpen: fileMenuOpen(state), editMenuOpen: editMenuOpen(state), @@ -802,6 +867,8 @@ const mapDispatchToProps = dispatch => ({ onRequestCloseLanguage: () => dispatch(closeLanguageMenu()), onClickLogin: () => dispatch(openLoginMenu()), onRequestCloseLogin: () => dispatch(closeLoginMenu()), + onRequestOpenAbout: () => dispatch(openAboutMenu()), + onRequestCloseAbout: () => dispatch(closeAboutMenu()), onClickNew: needSave => dispatch(requestNewProject(needSave)), onClickRemix: () => dispatch(remixProject()), onClickSave: () => dispatch(manualUpdateProject()), diff --git a/src/reducers/menus.js b/src/reducers/menus.js index 4cc494c60..fc3687f5a 100644 --- a/src/reducers/menus.js +++ b/src/reducers/menus.js @@ -1,6 +1,7 @@ const OPEN_MENU = 'scratch-gui/menus/OPEN_MENU'; const CLOSE_MENU = 'scratch-gui/menus/CLOSE_MENU'; +const MENU_ABOUT = 'aboutMenu'; const MENU_ACCOUNT = 'accountMenu'; const MENU_FILE = 'fileMenu'; const MENU_EDIT = 'editMenu'; @@ -9,6 +10,7 @@ const MENU_LOGIN = 'loginMenu'; const initialState = { + [MENU_ABOUT]: false, [MENU_ACCOUNT]: false, [MENU_FILE]: false, [MENU_EDIT]: false, @@ -39,6 +41,9 @@ const closeMenu = menu => ({ type: CLOSE_MENU, menu: menu }); +const openAboutMenu = () => openMenu(MENU_ABOUT); +const closeAboutMenu = () => closeMenu(MENU_ABOUT); +const aboutMenuOpen = state => state.scratchGui.menus[MENU_ABOUT]; const openAccountMenu = () => openMenu(MENU_ACCOUNT); const closeAccountMenu = () => closeMenu(MENU_ACCOUNT); const accountMenuOpen = state => state.scratchGui.menus[MENU_ACCOUNT]; @@ -58,6 +63,9 @@ const loginMenuOpen = state => state.scratchGui.menus[MENU_LOGIN]; export { reducer as default, initialState as menuInitialState, + openAboutMenu, + closeAboutMenu, + aboutMenuOpen, openAccountMenu, closeAccountMenu, accountMenuOpen, -- GitLab