From 7db0f8dcb2110b4ec8815bedc965cfbd01a59798 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 6 Oct 2017 01:07:59 +0200 Subject: Implement hotkeys for web UI (#5164) * Fix #2102 - Implement hotkeys Hotkeys on status list: - r to reply - m to mention author - f to favourite - b to boost - enter to open status - p to open author's profile - up or k to move up in the list - down or j to move down in the list - 1-9 to focus a status in one of the columns - n to focus the compose textarea - alt+n to start a brand new toot - backspace to navigate back * Add navigational hotkeys The key g followed by: - s: start - h: home - n: notifications - l: local timeline - t: federated timeline - f: favourites - u: own profile - p: pinned toots - b: blocked users - m: muted users * Add hotkey for focusing search, make escape un-focus compose/search * Fix focusing notifications column, fix hotkeys in compose textarea --- .../mastodon/features/compose/components/search.js | 2 + .../notifications/components/notification.js | 115 ++++++++--- .../containers/notification_container.js | 9 +- .../mastodon/features/notifications/index.js | 28 ++- app/javascript/mastodon/features/status/index.js | 151 ++++++++++++-- app/javascript/mastodon/features/ui/index.js | 223 +++++++++++++++++---- 6 files changed, 439 insertions(+), 89 deletions(-) (limited to 'app/javascript/mastodon/features') diff --git a/app/javascript/mastodon/features/compose/components/search.js b/app/javascript/mastodon/features/compose/components/search.js index 79abffad8..4c3f0dcb5 100644 --- a/app/javascript/mastodon/features/compose/components/search.js +++ b/app/javascript/mastodon/features/compose/components/search.js @@ -74,6 +74,8 @@ export default class Search extends React.PureComponent { if (e.key === 'Enter') { e.preventDefault(); this.props.onSubmit(); + } else if (e.key === 'Escape') { + document.querySelector('.ui').parentElement.focus(); } } diff --git a/app/javascript/mastodon/features/notifications/components/notification.js b/app/javascript/mastodon/features/notifications/components/notification.js index a608a5223..9d170cad5 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.js +++ b/app/javascript/mastodon/features/notifications/components/notification.js @@ -6,61 +6,126 @@ import AccountContainer from '../../../containers/account_container'; import { FormattedMessage } from 'react-intl'; import Permalink from '../../../components/permalink'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import { HotKeys } from 'react-hotkeys'; export default class Notification extends ImmutablePureComponent { + static contextTypes = { + router: PropTypes.object, + }; + static propTypes = { notification: ImmutablePropTypes.map.isRequired, hidden: PropTypes.bool, + onMoveUp: PropTypes.func.isRequired, + onMoveDown: PropTypes.func.isRequired, + onMention: PropTypes.func.isRequired, }; + handleMoveUp = () => { + const { notification, onMoveUp } = this.props; + onMoveUp(notification.get('id')); + } + + handleMoveDown = () => { + const { notification, onMoveDown } = this.props; + onMoveDown(notification.get('id')); + } + + handleOpen = () => { + const { notification } = this.props; + + if (notification.get('status')) { + this.context.router.history.push(`/statuses/${notification.get('status')}`); + } else { + this.handleOpenProfile(); + } + } + + handleOpenProfile = () => { + const { notification } = this.props; + this.context.router.history.push(`/accounts/${notification.getIn(['account', 'id'])}`); + } + + handleMention = e => { + e.preventDefault(); + + const { notification, onMention } = this.props; + onMention(notification.get('account'), this.context.router.history); + } + + getHandlers () { + return { + moveUp: this.handleMoveUp, + moveDown: this.handleMoveDown, + open: this.handleOpen, + openProfile: this.handleOpenProfile, + mention: this.handleMention, + reply: this.handleMention, + }; + } + renderFollow (account, link) { return ( -
-
-
- + +
+
+
+ +
+ +
- +
- -
+ ); } renderMention (notification) { - return