Skip to content
Snippets Groups Projects
Commit 0e973068 authored by Christopher Willis-Ford's avatar Christopher Willis-Ford
Browse files

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.
parent c04a12e9
No related branches found
No related tags found
No related merge requests found
...@@ -395,7 +395,6 @@ GUIComponent.propTypes = { ...@@ -395,7 +395,6 @@ GUIComponent.propTypes = {
onActivateCostumesTab: PropTypes.func, onActivateCostumesTab: PropTypes.func,
onActivateSoundsTab: PropTypes.func, onActivateSoundsTab: PropTypes.func,
onActivateTab: PropTypes.func, onActivateTab: PropTypes.func,
onClickAbout: PropTypes.func,
onClickAccountNav: PropTypes.func, onClickAccountNav: PropTypes.func,
onClickLogo: PropTypes.func, onClickLogo: PropTypes.func,
onCloseAccountNav: PropTypes.func, onCloseAccountNav: PropTypes.func,
......
...@@ -41,6 +41,9 @@ import { ...@@ -41,6 +41,9 @@ import {
saveProjectAsCopy saveProjectAsCopy
} from '../../reducers/project-state'; } from '../../reducers/project-state';
import { import {
openAboutMenu,
closeAboutMenu,
aboutMenuOpen,
openAccountMenu, openAccountMenu,
closeAccountMenu, closeAccountMenu,
accountMenuOpen, accountMenuOpen,
...@@ -282,6 +285,56 @@ class MenuBar extends React.Component { ...@@ -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 () { render () {
const saveNowMessage = ( const saveNowMessage = (
<FormattedMessage <FormattedMessage
...@@ -325,7 +378,7 @@ class MenuBar extends React.Component { ...@@ -325,7 +378,7 @@ class MenuBar extends React.Component {
</Button> </Button>
); );
// Show the About button only if we have a handler for it (like in the desktop app) // 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 ( return (
<Box <Box
className={classNames( className={classNames(
...@@ -701,6 +754,7 @@ class MenuBar extends React.Component { ...@@ -701,6 +754,7 @@ class MenuBar extends React.Component {
} }
MenuBar.propTypes = { MenuBar.propTypes = {
aboutMenuOpen: PropTypes.bool,
accountMenuOpen: PropTypes.bool, accountMenuOpen: PropTypes.bool,
authorId: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), authorId: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
authorThumbnailUrl: PropTypes.string, authorThumbnailUrl: PropTypes.string,
...@@ -728,7 +782,15 @@ MenuBar.propTypes = { ...@@ -728,7 +782,15 @@ MenuBar.propTypes = {
locale: PropTypes.string.isRequired, locale: PropTypes.string.isRequired,
loginMenuOpen: PropTypes.bool, loginMenuOpen: PropTypes.bool,
logo: PropTypes.string, 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, onClickAccount: PropTypes.func,
onClickEdit: PropTypes.func, onClickEdit: PropTypes.func,
onClickFile: PropTypes.func, onClickFile: PropTypes.func,
...@@ -743,6 +805,8 @@ MenuBar.propTypes = { ...@@ -743,6 +805,8 @@ MenuBar.propTypes = {
onOpenRegistration: PropTypes.func, onOpenRegistration: PropTypes.func,
onOpenTipLibrary: PropTypes.func, onOpenTipLibrary: PropTypes.func,
onProjectTelemetryEvent: PropTypes.func, onProjectTelemetryEvent: PropTypes.func,
onRequestOpenAbout: PropTypes.func,
onRequestCloseAbout: PropTypes.func,
onRequestCloseAccount: PropTypes.func, onRequestCloseAccount: PropTypes.func,
onRequestCloseEdit: PropTypes.func, onRequestCloseEdit: PropTypes.func,
onRequestCloseFile: PropTypes.func, onRequestCloseFile: PropTypes.func,
...@@ -771,6 +835,7 @@ const mapStateToProps = (state, ownProps) => { ...@@ -771,6 +835,7 @@ const mapStateToProps = (state, ownProps) => {
const loadingState = state.scratchGui.projectState.loadingState; const loadingState = state.scratchGui.projectState.loadingState;
const user = state.session && state.session.session && state.session.session.user; const user = state.session && state.session.session && state.session.session.user;
return { return {
aboutMenuOpen: aboutMenuOpen(state),
accountMenuOpen: accountMenuOpen(state), accountMenuOpen: accountMenuOpen(state),
fileMenuOpen: fileMenuOpen(state), fileMenuOpen: fileMenuOpen(state),
editMenuOpen: editMenuOpen(state), editMenuOpen: editMenuOpen(state),
...@@ -802,6 +867,8 @@ const mapDispatchToProps = dispatch => ({ ...@@ -802,6 +867,8 @@ const mapDispatchToProps = dispatch => ({
onRequestCloseLanguage: () => dispatch(closeLanguageMenu()), onRequestCloseLanguage: () => dispatch(closeLanguageMenu()),
onClickLogin: () => dispatch(openLoginMenu()), onClickLogin: () => dispatch(openLoginMenu()),
onRequestCloseLogin: () => dispatch(closeLoginMenu()), onRequestCloseLogin: () => dispatch(closeLoginMenu()),
onRequestOpenAbout: () => dispatch(openAboutMenu()),
onRequestCloseAbout: () => dispatch(closeAboutMenu()),
onClickNew: needSave => dispatch(requestNewProject(needSave)), onClickNew: needSave => dispatch(requestNewProject(needSave)),
onClickRemix: () => dispatch(remixProject()), onClickRemix: () => dispatch(remixProject()),
onClickSave: () => dispatch(manualUpdateProject()), onClickSave: () => dispatch(manualUpdateProject()),
......
const OPEN_MENU = 'scratch-gui/menus/OPEN_MENU'; const OPEN_MENU = 'scratch-gui/menus/OPEN_MENU';
const CLOSE_MENU = 'scratch-gui/menus/CLOSE_MENU'; const CLOSE_MENU = 'scratch-gui/menus/CLOSE_MENU';
const MENU_ABOUT = 'aboutMenu';
const MENU_ACCOUNT = 'accountMenu'; const MENU_ACCOUNT = 'accountMenu';
const MENU_FILE = 'fileMenu'; const MENU_FILE = 'fileMenu';
const MENU_EDIT = 'editMenu'; const MENU_EDIT = 'editMenu';
...@@ -9,6 +10,7 @@ const MENU_LOGIN = 'loginMenu'; ...@@ -9,6 +10,7 @@ const MENU_LOGIN = 'loginMenu';
const initialState = { const initialState = {
[MENU_ABOUT]: false,
[MENU_ACCOUNT]: false, [MENU_ACCOUNT]: false,
[MENU_FILE]: false, [MENU_FILE]: false,
[MENU_EDIT]: false, [MENU_EDIT]: false,
...@@ -39,6 +41,9 @@ const closeMenu = menu => ({ ...@@ -39,6 +41,9 @@ const closeMenu = menu => ({
type: CLOSE_MENU, type: CLOSE_MENU,
menu: 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 openAccountMenu = () => openMenu(MENU_ACCOUNT);
const closeAccountMenu = () => closeMenu(MENU_ACCOUNT); const closeAccountMenu = () => closeMenu(MENU_ACCOUNT);
const accountMenuOpen = state => state.scratchGui.menus[MENU_ACCOUNT]; const accountMenuOpen = state => state.scratchGui.menus[MENU_ACCOUNT];
...@@ -58,6 +63,9 @@ const loginMenuOpen = state => state.scratchGui.menus[MENU_LOGIN]; ...@@ -58,6 +63,9 @@ const loginMenuOpen = state => state.scratchGui.menus[MENU_LOGIN];
export { export {
reducer as default, reducer as default,
initialState as menuInitialState, initialState as menuInitialState,
openAboutMenu,
closeAboutMenu,
aboutMenuOpen,
openAccountMenu, openAccountMenu,
closeAccountMenu, closeAccountMenu,
accountMenuOpen, accountMenuOpen,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment