From c23fb6ac803d6edc6f3f3a7e1fcd6f45ce333070 Mon Sep 17 00:00:00 2001 From: Grant Richmond Date: Sat, 8 Dec 2018 18:06:04 +0100 Subject: [PATCH] add a help modal that explains all the shortcuts --- src/actions/app.js | 4 + src/components/GlobalShotcuts/index.js | 13 +- src/components/SettingsModal/index.js | 33 ++--- src/components/SettingsModal/style.js | 5 +- src/components/ShortcutHelp/ShortcutTable.js | 38 ++++++ src/components/ShortcutHelp/index.js | 121 +++++++++++++++++++ src/containers/App.js | 2 + src/modules/keymap.js | 23 ++-- src/reducers/app.js | 4 + 9 files changed, 210 insertions(+), 33 deletions(-) create mode 100644 src/components/ShortcutHelp/ShortcutTable.js create mode 100644 src/components/ShortcutHelp/index.js diff --git a/src/actions/app.js b/src/actions/app.js index 67b1050..60dfb24 100644 --- a/src/actions/app.js +++ b/src/actions/app.js @@ -23,3 +23,7 @@ export const focusComponent = component => ({ type: 'SET_FOCUSED_COMPONENT', component, }) + +export const toggleShortcutHelp = () => ({ + type: 'TOGGLE_SHORTCUT_HELP', +}) diff --git a/src/components/GlobalShotcuts/index.js b/src/components/GlobalShotcuts/index.js index 076c0dc..b4d73f5 100644 --- a/src/components/GlobalShotcuts/index.js +++ b/src/components/GlobalShotcuts/index.js @@ -7,6 +7,7 @@ import { selectChannel, toggleChannelsMenu, focusComponent, + toggleShortcutHelp, } from '../../actions' class GlobalShortcutHandler extends Component { @@ -16,7 +17,13 @@ class GlobalShortcutHandler extends Component { } handleShortcuts(action) { - const { channels, selectChannel, history, focusComponent } = this.props + const { + channels, + selectChannel, + history, + focusComponent, + toggleShortcutHelp, + } = this.props if (action.indexOf('CHANNEL_') === 0) { // Switch channel @@ -40,7 +47,7 @@ class GlobalShortcutHandler extends Component { focusComponent('channels') break case 'HELP': - alert("Sorry, I can't help you yet") + toggleShortcutHelp() break case 'KONAMI': alert('Look at you. You are very clever') @@ -69,7 +76,7 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => bindActionCreators( - { selectChannel, toggleChannelsMenu, focusComponent }, + { selectChannel, toggleChannelsMenu, focusComponent, toggleShortcutHelp }, dispatch ) diff --git a/src/components/SettingsModal/index.js b/src/components/SettingsModal/index.js index 0e02200..7de2905 100644 --- a/src/components/SettingsModal/index.js +++ b/src/components/SettingsModal/index.js @@ -35,37 +35,37 @@ class SettingsModal extends Component { } render() { + const { open } = this.state + const { classes, children, singleColumn, ...dialogProps } = this.props return ( - + {this.props.title} -
- - {this.props.children} +
+ + {children}
@@ -73,11 +73,14 @@ class SettingsModal extends Component { } } -SettingsModal.defaultProps = {} +SettingsModal.defaultProps = { + singleColumn: false, +} SettingsModal.propTypes = { title: PropTypes.string.isRequired, onClose: PropTypes.func, + singleColumn: PropTypes.bool.isRequired, } export default withRouter(withStyles(styles)(SettingsModal)) diff --git a/src/components/SettingsModal/style.js b/src/components/SettingsModal/style.js index fc1f085..55378a5 100644 --- a/src/components/SettingsModal/style.js +++ b/src/components/SettingsModal/style.js @@ -12,7 +12,10 @@ export default theme => ({ flex: 1, fontWeight: 'normal', }, - content: { + singleColumn: { + display: 'block', + }, + twoColumns: { [theme.breakpoints.up('sm')]: { display: 'flex', flexWrap: 'wrap', diff --git a/src/components/ShortcutHelp/ShortcutTable.js b/src/components/ShortcutHelp/ShortcutTable.js new file mode 100644 index 0000000..098b345 --- /dev/null +++ b/src/components/ShortcutHelp/ShortcutTable.js @@ -0,0 +1,38 @@ +import React from 'react' +import Table from '@material-ui/core/Table' +import TableBody from '@material-ui/core/TableBody' +import TableCell from '@material-ui/core/TableCell' +import TableRow from '@material-ui/core/TableRow' +import Typography from '@material-ui/core/Typography' +import Chip from '@material-ui/core/Chip' + +const ShortcutTable = ({ title, keys }) => ( +
+ + {title} + + + + {keys.map(key => ( + + {key.name} + + {key.shortcuts.map(key => ( + + ))} + + + ))} + +
+
+) + +export default ShortcutTable diff --git a/src/components/ShortcutHelp/index.js b/src/components/ShortcutHelp/index.js new file mode 100644 index 0000000..c9c5994 --- /dev/null +++ b/src/components/ShortcutHelp/index.js @@ -0,0 +1,121 @@ +import React from 'react' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import SettingsModal from '../SettingsModal' +import { toggleShortcutHelp } from '../../actions' +import keymap from '../../modules/keymap' +import ShortcutTable from './ShortcutTable' + +const globalKeys = [ + { + name: 'Focus Channels List', + shortcuts: keymap.GLOBAL.FOCUS_CHANNEL_LIST, + }, + { + name: 'Show Keyboard Shorcuts', + shortcuts: keymap.GLOBAL.HELP, + }, + { + name: 'Open New Post Editor', + shortcuts: keymap.GLOBAL.NEW_POST, + }, + { + name: 'Load Channel', + shortcuts: ['ctrl+1-9', 'meta+1-9', 'alt+1-9'], + }, +] + +const channelListKeys = [ + { + name: 'Next Channel', + shortcuts: keymap.CHANNEL_LIST.NEXT, + }, + { + name: 'Previous Channel', + shortcuts: keymap.CHANNEL_LIST.PREVIOUS, + }, + { + name: 'Load Channel', + shortcuts: keymap.CHANNEL_LIST.SELECT_CHANNEL, + }, +] + +const channelKeys = [ + { + name: 'Next Post', + shortcuts: keymap.TIMELINE.NEXT, + }, + { + name: 'Previous Post', + shortcuts: keymap.TIMELINE.PREVIOUS, + }, + { + name: 'Select Post', + shortcuts: keymap.TIMELINE.SELECT_POST, + }, + { + name: 'Focus Channel List', + shortcuts: keymap.TIMELINE.FOCUS_CHANNEL_LIST, + }, + { + name: 'Toggle Selected Post Read', + shortcuts: keymap.TIMELINE.MARK_READ, + }, +] + +const singlePostKeys = [ + { + name: 'Next Post', + shortcuts: keymap.POST.NEXT, + }, + { + name: 'Open Post Url', + shortcuts: keymap.POST.OPEN, + }, + { + name: 'Toggle Post Read', + shortcuts: keymap.POST.TOGGLE_READ, + }, + { + name: 'Back to Post List', + shortcuts: keymap.POST.TO_TIMELINE, + }, + { + name: 'Scroll Up', + shortcuts: keymap.POST.SCROLL_UP, + }, + { + name: 'Scroll Down', + shortcuts: keymap.POST.SCROLL_DOWN, + }, +] + +const ShortcutHelp = ({ open, toggleShortcutHelp }) => { + return ( + (open ? toggleShortcutHelp() : null)} + singleColumn + disableAutoFocus + > + + + + + + ) +} + +const mapStateToProps = state => ({ + open: state.app.get('shortcutHelpOpen'), +}) + +const mapDispatchToProps = dispatch => + bindActionCreators({ toggleShortcutHelp }, dispatch) + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ShortcutHelp) diff --git a/src/containers/App.js b/src/containers/App.js index f4916d6..05a6b91 100644 --- a/src/containers/App.js +++ b/src/containers/App.js @@ -15,6 +15,7 @@ import Notification from '../components/Notification' import MicropubEditor from '../components/MicropubEditorFull' import ErrorBoundary from '../components/ErrorBoundary' import GlobalShortcuts from '../components/GlobalShotcuts' +import ShortcutHelp from '../components/ShortcutHelp' import keymap from '../modules/keymap' import style from './style' @@ -61,6 +62,7 @@ class App extends Component { /> + diff --git a/src/modules/keymap.js b/src/modules/keymap.js index d5d71b9..0ff057d 100644 --- a/src/modules/keymap.js +++ b/src/modules/keymap.js @@ -9,18 +9,18 @@ export default { PREVIOUS: ['k', 'up'], SELECT_POST: ['l', 'enter', 'right', 'v'], FOCUS_CHANNEL_LIST: ['h', 'left'], - MARK_READ: 'm', + MARK_READ: ['m'], }, POST: { - SCROLL_DOWN: 'j', - SCROLL_UP: 'k', - TO_TIMELINE: 'h', - NEXT: 'space', - OPEN: 'v', - TOGGLE_READ: 'm', + SCROLL_DOWN: ['j'], + SCROLL_UP: ['k'], + TO_TIMELINE: ['h'], + NEXT: ['space'], + OPEN: ['v'], + TOGGLE_READ: ['m'], }, GLOBAL: { - KONAMI: 'up up down down left right left right b a', + KONAMI: ['up up down down left right left right b a'], CHANNEL_1: ['ctrl+1', 'meta+1', 'alt+1'], CHANNEL_2: ['ctrl+2', 'meta+2', 'alt+2'], CHANNEL_3: ['ctrl+3', 'meta+3', 'alt+3'], @@ -32,20 +32,15 @@ export default { CHANNEL_9: ['ctrl+9', 'meta+9', 'alt+9'], NEW_POST: ['ctrl+n', 'meta+n', 'alt+n'], FOCUS_CHANNEL_LIST: ['c'], - HELP: '?', + HELP: ['?'], }, } /** - * TODO: Focus channel list or timeline on load * TODO: Classic view needs to mark stuff as read * TODO: Global keymapping for: * Open notifications * Mark channel read * Jump to channel list * Jump to timeline - * TODO: Gallery view controls - * TODO: Timeline view contols - * TODO: Map view controls - * TODO: Shortcuts help view to show what all the shortcuts do */ diff --git a/src/reducers/app.js b/src/reducers/app.js index 12a109f..264eefd 100644 --- a/src/reducers/app.js +++ b/src/reducers/app.js @@ -8,6 +8,7 @@ const defaultState = new Map({ timelineAfter: '', notifications: [], focusedComponent: null, + shortcutHelpOpen: false, theme: localStorage.getItem('together-theme') || getTheme() || 'light', }) @@ -53,6 +54,9 @@ export default (state = defaultState, payload) => { case 'SET_FOCUSED_COMPONENT': { return state.set('focusedComponent', payload.component) } + case 'TOGGLE_SHORTCUT_HELP': { + return state.set('shortcutHelpOpen', !state.get('shortcutHelpOpen')) + } default: { return state }