-
-
+
`;
diff --git a/components/file_upload/file_upload.jsx b/components/file_upload/file_upload.jsx
index 03fb87337e4f..3665c1e33924 100644
--- a/components/file_upload/file_upload.jsx
+++ b/components/file_upload/file_upload.jsx
@@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import ReactDOM from 'react-dom';
import {defineMessages, FormattedMessage, injectIntl} from 'react-intl';
+import {Tooltip} from 'react-bootstrap';
import dragster from 'utils/dragster';
import Constants from 'utils/constants';
@@ -30,6 +31,8 @@ import MenuWrapper from 'components/widgets/menu/menu_wrapper';
import Menu from 'components/widgets/menu/menu';
import AttachmentIcon from 'components/widgets/icons/attachment_icon';
+import KeyboardShortcutSequence, {KEYBOARD_SHORTCUTS} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
+import OverlayTrigger from 'components/overlay_trigger';
const holders = defineMessages({
limited: {
@@ -695,9 +698,24 @@ export class FileUpload extends PureComponent {
}
return (
-
- {bodyAction}
-
+
+
+
+ }
+ >
+
+ {bodyAction}
+
+
);
}
}
diff --git a/components/global/at_mentions_button/at_mentions_button.tsx b/components/global/at_mentions_button/at_mentions_button.tsx
index a531bcc608df..7a780496da84 100644
--- a/components/global/at_mentions_button/at_mentions_button.tsx
+++ b/components/global/at_mentions_button/at_mentions_button.tsx
@@ -5,7 +5,6 @@ import React from 'react';
import {Tooltip} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
-
import IconButton from '@mattermost/compass-components/components/icon-button';
import {closeRightHandSide, showMentions} from 'actions/views/rhs';
@@ -13,6 +12,7 @@ import OverlayTrigger from 'components/overlay_trigger';
import {getIsRhsOpen, getRhsState} from 'selectors/rhs';
import {GlobalState} from 'types/store';
import Constants, {RHSStates} from 'utils/constants';
+import KeyboardShortcutSequence, {KEYBOARD_SHORTCUTS} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
const AtMentionsButton = (): JSX.Element => {
const dispatch = useDispatch();
@@ -34,6 +34,11 @@ const AtMentionsButton = (): JSX.Element => {
id='channel_header.recentMentions'
defaultMessage='Recent mentions'
/>
+
);
diff --git a/components/global/history_buttons/history_buttons.tsx b/components/global/history_buttons/history_buttons.tsx
index 40b8691cd612..89ab06eccf45 100644
--- a/components/global/history_buttons/history_buttons.tsx
+++ b/components/global/history_buttons/history_buttons.tsx
@@ -3,11 +3,18 @@
import React from 'react';
import styled from 'styled-components';
+import {Tooltip} from 'react-bootstrap';
import IconButton from '@mattermost/compass-components/components/icon-button';
import {trackEvent} from 'actions/telemetry_actions';
import * as Utils from 'utils/utils';
import {browserHistory} from 'utils/browser_history';
+import Constants from 'utils/constants';
+import KeyboardShortcutSequence, {
+ KEYBOARD_SHORTCUTS,
+ KeyboardShortcutDescriptor,
+} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
+import OverlayTrigger from 'components/overlay_trigger';
const HistoryButtonsContainer = styled.nav`
display: flex;
@@ -19,6 +26,17 @@ const HistoryButtonsContainer = styled.nav`
`;
const HistoryButtons = (): JSX.Element => {
+ const getTooltip = (shortcut: KeyboardShortcutDescriptor) => (
+
+
+
+ );
const goBack = () => {
trackEvent('ui', 'ui_history_back');
browserHistory.goBack();
@@ -31,22 +49,36 @@ const HistoryButtons = (): JSX.Element => {
return (
-
-
+
+
+
+
+
+
);
};
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_modal/__snapshots__/keyboard_shortcuts_modal.test.tsx.snap b/components/keyboard_shortcuts/keyboard_shortcuts_modal/__snapshots__/keyboard_shortcuts_modal.test.tsx.snap
new file mode 100644
index 000000000000..5e072d0119e1
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_modal/__snapshots__/keyboard_shortcuts_modal.test.tsx.snap
@@ -0,0 +1,64 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`components/KeyboardShortcutsModal should match snapshot modal 1`] = `
+
+
+
+
+
+`;
diff --git a/sass/routes/_shortcuts-modal.scss b/components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.scss
similarity index 68%
rename from sass/routes/_shortcuts-modal.scss
rename to components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.scss
index ee82d6319e1f..c97060c99baa 100644
--- a/sass/routes/_shortcuts-modal.scss
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.scss
@@ -54,16 +54,6 @@
margin-right: 5px;
}
}
-
- // TODO: It probably makes sense to switch to
component
- // in order to have universal shortcut key appearance
- .shortcut-key {
- padding: 4px 6px;
- margin: 5px 0 5px 5px;
- border-radius: 3px;
- font-size: 12px;
- font-weight: 500;
- }
}
}
@@ -84,26 +74,6 @@
}
}
-.shortcut-line {
- margin: 16px 0;
-
- span {
- &:first-child {
- margin-right: 5px;
- }
- }
-
- // TODO: It probably makes sense to switch to component
- // in order to have universal shortcut key appearance
- .shortcut-key {
- padding: 4px 6px;
- margin: 5px 0 5px 5px;
- border-radius: 3px;
- font-size: 0.9em;
- font-weight: 500;
- }
-}
-
@media (max-height: 800px) {
.modal {
.shortcuts-modal {
@@ -116,8 +86,4 @@
}
}
}
-
- .shortcut-line {
- margin-top: 14px;
- }
}
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.test.tsx b/components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.test.tsx
new file mode 100644
index 000000000000..357cba868928
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.test.tsx
@@ -0,0 +1,17 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import React from 'react';
+
+import {mountWithIntl} from 'tests/helpers/intl-test-helper';
+import KeyboardShortcutsModal from 'components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal';
+
+describe('components/KeyboardShortcutsModal', () => {
+ test('should match snapshot modal', () => {
+ const wrapper = mountWithIntl(
+ ,
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.tsx b/components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.tsx
new file mode 100644
index 000000000000..4f6761e9d35a
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal.tsx
@@ -0,0 +1,169 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import React, {useEffect, useState} from 'react';
+import {Modal} from 'react-bootstrap';
+import {defineMessages, useIntl} from 'react-intl';
+
+import ModalStore from 'stores/modal_store.jsx';
+import Constants from 'utils/constants';
+import {t} from 'utils/i18n';
+import * as Utils from 'utils/utils';
+import KeyboardShortcutSequence, {
+ KEYBOARD_SHORTCUTS,
+} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
+import './keyboard_shortcuts_modal.scss';
+
+const modalMessages = defineMessages({
+ msgHeader: {
+ id: t('shortcuts.msgs.header'),
+ defaultMessage: 'Messages',
+ },
+ msgInputHeader: {
+ id: t('shortcuts.msgs.input.header'),
+ defaultMessage: 'Works inside an empty input field',
+ },
+ filesHeader: {
+ id: t('shortcuts.files.header'),
+ defaultMessage: 'Files',
+ },
+ browserHeader: {
+ id: t('shortcuts.browser.header'),
+ defaultMessage: 'Built-in Browser Commands',
+ },
+ msgCompHeader: {
+ id: t('shortcuts.msgs.comp.header'),
+ defaultMessage: 'Autocomplete',
+ },
+ browserInputHeader: {
+ id: t('shortcuts.browser.input.header'),
+ defaultMessage: 'Works inside an input field',
+ },
+ msgMarkdownHeader: {
+ id: t('shortcuts.msgs.markdown.header'),
+ defaultMessage: 'Formatting',
+ },
+ info: {
+ id: t('shortcuts.info'),
+ defaultMessage:
+ 'Begin a message with / for a list of all the commands at your disposal.',
+ },
+ navHeader: {
+ id: t('shortcuts.nav.header'),
+ defaultMessage: 'Navigation',
+ },
+});
+
+const KeyboardShortcutsModal = (): JSX.Element => {
+ const [show, setShow] = useState(false);
+
+ useEffect(() => {
+ //toggles the state of shortcut dialog
+ const handleToggle = (): void => setShow(!show);
+ ModalStore.addModalListener(Constants.ActionTypes.TOGGLE_SHORTCUTS_MODAL, handleToggle);
+ return () => {
+ ModalStore.removeModalListener(Constants.ActionTypes.TOGGLE_SHORTCUTS_MODAL, handleToggle);
+ };
+ }, []);
+
+ const handleHide = (): void => setShow(false);
+ const {formatMessage} = useIntl();
+ const isLinux = Utils.isLinux();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
{formatMessage(modalMessages.navHeader)}
+
+
+
+
+ {!isLinux && }
+ {!isLinux && }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{formatMessage(modalMessages.msgHeader)}
+
{formatMessage(modalMessages.msgInputHeader)}
+
+
+
+
+
+
+
+
{formatMessage(modalMessages.msgCompHeader)}
+
+
+
+
+
+
{formatMessage(modalMessages.msgMarkdownHeader)}
+
+
+
+
+
+
+
+
+
+
+
+
{formatMessage(modalMessages.filesHeader)}
+
+
+
+
{formatMessage(modalMessages.browserHeader)}
+
+
+
+
+ {formatMessage(modalMessages.browserInputHeader)}
+
+
+
+
+
+
+
+
+
+ {formatMessage(modalMessages.info)}
+
+
+
+ );
+};
+
+export default KeyboardShortcutsModal;
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_sequence/__snapshots__/keyboard_shortcuts_sequence.test.tsx.snap b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/__snapshots__/keyboard_shortcuts_sequence.test.tsx.snap
new file mode 100644
index 000000000000..bb6161b8aaf6
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/__snapshots__/keyboard_shortcuts_sequence.test.tsx.snap
@@ -0,0 +1,215 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`components/shortcuts/KeyboardShortcutsSequence should create sequence with order 1`] = `
+
+
+
+
+ Ctrl
+
+
+
+
+ Alt
+
+
+
+
+ 3
+
+
+
+
+`;
+
+exports[`components/shortcuts/KeyboardShortcutsSequence should match snapshot when used for modal with description 1`] = `
+
+
+
+ Keyboard Shortcuts
+
+
+
+ ⌘
+
+
+
+
+ /
+
+
+
+
+`;
+
+exports[`components/shortcuts/KeyboardShortcutsSequence should render sequence hoisting description 1`] = `
+
+ Keyboard Shortcuts
+
+
+
+ ⌘
+
+
+
+
+ /
+
+
+
+
+`;
+
+exports[`components/shortcuts/KeyboardShortcutsSequence should render sequence without description 1`] = `
+
+
+
+
+ ⌘
+
+
+
+
+ /
+
+
+
+
+`;
+
+exports[`components/shortcuts/KeyboardShortcutsSequence should render sequence without description 2`] = `
+
+
+
+ Keyboard Shortcuts
+
+
+
+ ⌘
+
+
+
+
+ /
+
+
+
+
+`;
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_sequence/index.ts b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/index.ts
new file mode 100644
index 000000000000..b7db22946cbd
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/index.ts
@@ -0,0 +1,7 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import KeyboardShortcutSequence from './keyboard_shortcuts_sequence';
+
+export * from './keyboard_shortcuts';
+export default KeyboardShortcutSequence;
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts.ts b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts.ts
new file mode 100644
index 000000000000..2015a413e28f
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts.ts
@@ -0,0 +1,307 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {MessageDescriptor} from 'react-intl';
+
+import {t} from 'utils/i18n';
+
+export type KeyboardShortcutDescriptor = MessageDescriptor | {default: MessageDescriptor; mac?: MessageDescriptor};
+
+export function isMessageDescriptor(descriptor: KeyboardShortcutDescriptor): descriptor is MessageDescriptor {
+ return Boolean((descriptor as MessageDescriptor).id);
+}
+
+export const KEYBOARD_SHORTCUTS = {
+ mainHeader: {
+ default: {
+ id: t('shortcuts.header'),
+ defaultMessage: 'Keyboard Shortcuts\tCtrl|/',
+ },
+ mac: {
+ id: t('shortcuts.header.mac'),
+ defaultMessage: 'Keyboard Shortcuts\t⌘|/',
+ },
+ },
+ navPrev: {
+ default: {
+ id: t('shortcuts.nav.prev'),
+ defaultMessage: 'Previous channel:\tAlt|Up',
+ },
+ mac: {
+ id: t('shortcuts.nav.prev.mac'),
+ defaultMessage: 'Previous channel:\t⌥|Up',
+ },
+ },
+ navNext: {
+ default: {
+ id: t('shortcuts.nav.next'),
+ defaultMessage: 'Next channel:\tAlt|Down',
+ },
+ mac: {
+ id: t('shortcuts.nav.next.mac'),
+ defaultMessage: 'Next channel:\t⌥|Down',
+ },
+ },
+ navUnreadPrev: {
+ default: {
+ id: t('shortcuts.nav.unread_prev'),
+ defaultMessage: 'Previous unread channel:\tAlt|Shift|Up',
+ },
+ mac: {
+ id: t('shortcuts.nav.unread_prev.mac'),
+ defaultMessage: 'Previous unread channel:\t⌥|Shift|Up',
+ },
+ },
+ navUnreadNext: {
+ default: {
+ id: t('shortcuts.nav.unread_next'),
+ defaultMessage: 'Next unread channel:\tAlt|Shift|Down',
+ },
+ mac: {
+ id: t('shortcuts.nav.unread_next.mac'),
+ defaultMessage: 'Next unread channel:\t⌥|Shift|Down',
+ },
+ },
+ teamNavPrev: {
+ default: {
+ id: t('shortcuts.team_nav.prev'),
+ defaultMessage: 'Previous team:\tCtrl|Alt|Up',
+ },
+ mac: {
+ id: t('shortcuts.team_nav.prev.mac'),
+ defaultMessage: 'Previous team:\t⌘|⌥|Up',
+ },
+ },
+ teamNavNext: {
+ default: {
+ id: t('shortcuts.team_nav.next'),
+ defaultMessage: 'Next team:\tCtrl|Alt|Down',
+ },
+ mac: {
+ id: t('shortcuts.team_nav.next.mac'),
+ defaultMessage: 'Next team:\t⌘|⌥|Down',
+ },
+ },
+ teamNavSwitcher: {
+ default: {
+ id: t('shortcuts.team_nav.switcher'),
+ defaultMessage: 'Switch to a specific team:\tCtrl|Alt|[1-9]',
+ },
+ mac: {
+ id: t('shortcuts.team_nav.switcher.mac'),
+ defaultMessage: 'Switch to a specific team:\t⌘|⌥|[1-9]',
+ },
+ },
+ teamNavigation: {
+ default: {
+ id: t('team.button.tooltip'),
+ defaultMessage: 'Ctrl|Alt|{order}',
+ },
+ mac: {
+ id: t('team.button.tooltip.mac'),
+ defaultMessage: '⌘|⌥|{order}',
+ },
+ },
+ navSwitcher: {
+ default: {
+ id: t('shortcuts.nav.switcher'),
+ defaultMessage: 'Quick channel switcher:\tCtrl|K',
+ },
+ mac: {
+ id: t('shortcuts.nav.switcher.mac'),
+ defaultMessage: 'Quick channel switcher:\t⌘|K',
+ },
+ },
+ navDMMenu: {
+ default: {
+ id: t('shortcuts.nav.direct_messages_menu'),
+ defaultMessage: 'Direct messages menu:\tCtrl|Shift|K',
+ },
+ mac: {
+ id: t('shortcuts.nav.direct_messages_menu.mac'),
+ defaultMessage: 'Direct messages menu:\t⌘|Shift|K',
+ },
+ },
+ navSettings: {
+ default: {
+ id: t('shortcuts.nav.settings'),
+ defaultMessage: 'Account settings:\tCtrl|Shift|A',
+ },
+ mac: {
+ id: t('shortcuts.nav.settings.mac'),
+ defaultMessage: 'Account settings:\t⌘|Shift|A',
+ },
+ },
+ navMentions: {
+ default: {
+ id: t('shortcuts.nav.recent_mentions'),
+ defaultMessage: 'Recent mentions:\tCtrl|Shift|M',
+ },
+ mac: {
+ id: t('shortcuts.nav.recent_mentions.mac'),
+ defaultMessage: 'Recent mentions:\t⌘|Shift|M',
+ },
+ },
+ navFocusCenter: {
+ default: {
+ id: t('shortcuts.nav.focus_center'),
+ defaultMessage: 'Set focus to input field:\tCtrl|Shift|L',
+ },
+ mac: {
+ id: t('shortcuts.nav.focus_center.mac'),
+ defaultMessage: 'Set focus to input field:\t⌘|Shift|L',
+ },
+ },
+ navOpenCloseSidebar: {
+ default: {
+ id: t('shortcuts.nav.open_close_sidebar'),
+ defaultMessage: 'Open or close the right sidebar\tCtrl|.',
+ },
+ mac: {
+ id: t('shortcuts.nav.open_close_sidebar.mac'),
+ defaultMessage: 'Open or close the right sidebar\t⌘|.',
+ },
+ },
+ msgEdit: {
+ id: t('shortcuts.msgs.edit'),
+ defaultMessage: 'Edit last message in channel:\tUp',
+ },
+ msgReply: {
+ id: t('shortcuts.msgs.reply'),
+ defaultMessage: 'Reply to last message in channel:\tShift|Up',
+ },
+ msgReprintPrev: {
+ default: {
+ id: t('shortcuts.msgs.reprint_prev'),
+ defaultMessage: 'Reprint previous message:\tCtrl|Up',
+ },
+ mac: {
+ id: t('shortcuts.msgs.reprint_prev.mac'),
+ defaultMessage: 'Reprint previous message:\t⌘|Up',
+ },
+ },
+ msgReprintNext: {
+ default: {
+ id: t('shortcuts.msgs.reprint_next'),
+ defaultMessage: 'Reprint next message:\tCtrl|Down',
+ },
+ mac: {
+ id: t('shortcuts.msgs.reprint_next.mac'),
+ defaultMessage: 'Reprint next message:\t⌘|Down',
+ },
+ },
+ msgCompUsername: {
+ id: t('shortcuts.msgs.comp.username'),
+ defaultMessage: 'Username:\t@|[a-z]|Tab',
+ },
+ msgCompChannel: {
+ id: t('shortcuts.msgs.comp.channel'),
+ defaultMessage: 'Channel:\t~|[a-z]|Tab',
+ },
+ msgCompEmoji: {
+ id: t('shortcuts.msgs.comp.emoji'),
+ defaultMessage: 'Emoji:\t:|[a-z]|Tab',
+ },
+ msgLastReaction: {
+ default: {
+ id: t('shortcuts.msgs.comp.last_reaction'),
+ defaultMessage: 'React to last message:\tCtrl|Shift|\u29F5',
+ },
+ mac: {
+ id: t('shortcuts.msgs.comp.last_reaction.mac'),
+ defaultMessage: 'React to last message:\t⌘|Shift|\u29F5',
+ },
+ },
+ msgMarkdownBold: {
+ default: {
+ id: t('shortcuts.msgs.markdown.bold'),
+ defaultMessage: 'Bold:\tCtrl|B',
+ },
+ mac: {
+ id: t('shortcuts.msgs.markdown.bold.mac'),
+ defaultMessage: 'Bold:\t⌘|B',
+ },
+ },
+ msgMarkdownItalic: {
+ default: {
+ id: t('shortcuts.msgs.markdown.italic'),
+ defaultMessage: 'Italic:\tCtrl|I',
+ },
+ mac: {
+ id: t('shortcuts.msgs.markdown.italic.mac'),
+ defaultMessage: 'Italic:\t⌘|I',
+ },
+ },
+ msgMarkdownLink: {
+ default: {
+ id: t('shortcuts.msgs.markdown.link'),
+ defaultMessage: 'Link:\tCtrl|Alt|K',
+ },
+ mac: {
+ id: t('shortcuts.msgs.markdown.link.mac'),
+ defaultMessage: 'Link:\t⌘|Alt|K',
+ },
+ },
+ filesUpload: {
+ default: {
+ id: t('shortcuts.files.upload'),
+ defaultMessage: 'Upload files:\tCtrl|U',
+ },
+ mac: {
+ id: t('shortcuts.files.upload.mac'),
+ defaultMessage: 'Upload files:\t⌘|U',
+ },
+ },
+ browserChannelPrev: {
+ default: {
+ id: t('shortcuts.browser.channel_prev'),
+ defaultMessage: 'Back in history:\tAlt|Left',
+ },
+ mac: {
+ id: t('shortcuts.browser.channel_prev.mac'),
+ defaultMessage: 'Back in history:\t⌘|[',
+ },
+ },
+ browserChannelNext: {
+ default: {
+ id: t('shortcuts.browser.channel_next'),
+ defaultMessage: 'Forward in history:\tAlt|Right',
+ },
+ mac: {
+ id: t('shortcuts.browser.channel_next.mac'),
+ defaultMessage: 'Forward in history:\t⌘|]',
+ },
+ },
+ browserFontIncrease: {
+ default: {
+ id: t('shortcuts.browser.font_increase'),
+ defaultMessage: 'Zoom in:\tCtrl|+',
+ },
+ mac: {
+ id: t('shortcuts.browser.font_increase.mac'),
+ defaultMessage: 'Zoom in:\t⌘|+',
+ },
+ },
+ browserFontDecrease: {
+ default: {
+ id: t('shortcuts.browser.font_decrease'),
+ defaultMessage: 'Zoom out:\tCtrl|-',
+ },
+ mac: {
+ id: t('shortcuts.browser.font_decrease.mac'),
+ defaultMessage: 'Zoom out:\t⌘|-',
+ },
+ },
+ browserHighlightPrev: {
+ id: t('shortcuts.browser.highlight_prev'),
+ defaultMessage: 'Highlight text to the previous line:\tShift|Up',
+ },
+ browserHighlightNext: {
+ id: t('shortcuts.browser.highlight_next'),
+ defaultMessage: 'Highlight text to the next line:\tShift|Down',
+ },
+ browserNewline: {
+ id: t('shortcuts.browser.newline'),
+ defaultMessage: 'Create a new line:\tShift|Enter',
+ },
+};
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.scss b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.scss
new file mode 100644
index 000000000000..e3532fe3999c
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.scss
@@ -0,0 +1,30 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+.shortcut-line {
+ margin: 16px 0;
+
+ span {
+ &:first-child {
+ margin-right: 5px;
+ }
+ }
+
+ .shortcut-key {
+ padding: 2px 5px;
+
+ + .shortcut-key {
+ margin-left: 2px;
+ }
+ }
+}
+
+.tooltip-inner .shortcut-line {
+ margin: 4px 0;
+}
+
+@media (max-height: 800px) {
+ .shortcut-line {
+ margin-top: 14px;
+ }
+}
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.test.tsx b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.test.tsx
new file mode 100644
index 000000000000..79d841d2cdd9
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.test.tsx
@@ -0,0 +1,98 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import React from 'react';
+
+import {mountWithIntl} from 'tests/helpers/intl-test-helper';
+
+import KeyboardShortcutsSequence from './keyboard_shortcuts_sequence';
+
+import KeyboardShortcutSequence, {KEYBOARD_SHORTCUTS} from './index';
+
+describe('components/shortcuts/KeyboardShortcutsSequence', () => {
+ test('should match snapshot when used for modal with description', () => {
+ const wrapper = mountWithIntl(
+ ,
+ );
+
+ const tag = {'Keyboard Shortcuts'};
+ expect(wrapper.contains(tag)).toEqual(true);
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('.shortcut-key--tooltip')).toHaveLength(0);
+ expect(wrapper.find('.shortcut-key--shortcut-modal')).toHaveLength(2);
+ });
+
+ test('should render sequence without description', () => {
+ const wrapper = mountWithIntl(
+ ,
+ );
+
+ const tag = {'Keyboard Shortcuts'};
+ expect(wrapper.contains(tag)).toEqual(false);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('should render sequence without description', () => {
+ const wrapper = mountWithIntl(
+ ,
+ );
+
+ const tag = {'Keyboard Shortcuts'};
+ expect(wrapper.contains(tag)).toEqual(true);
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('.shortcut-key--tooltip')).toHaveLength(2);
+ expect(wrapper.find('.shortcut-key--shortcut-modal')).toHaveLength(0);
+ });
+ test('should render sequence hoisting description', () => {
+ const wrapper = mountWithIntl(
+ ,
+ );
+
+ const tag = {'Keyboard Shortcuts'};
+ expect(wrapper.contains(tag)).toEqual(false);
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('.shortcut-key--tooltip')).toHaveLength(2);
+ expect(wrapper.find('.shortcut-key--shortcut-modal')).toHaveLength(0);
+ });
+
+ test('should create sequence with order', () => {
+ const order = 3;
+ const wrapper = mountWithIntl(
+ ,
+ );
+ expect(wrapper).toMatchSnapshot();
+ const tag = {'Keyboard Shortcuts'};
+ expect(wrapper.contains(tag)).toEqual(false);
+ expect(wrapper.find('.shortcut-key--tooltip')).toHaveLength(3);
+ expect(wrapper.find('.shortcut-key--shortcut-modal')).toHaveLength(0);
+ });
+});
diff --git a/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.tsx b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.tsx
new file mode 100644
index 000000000000..5a0e27b289c8
--- /dev/null
+++ b/components/keyboard_shortcuts/keyboard_shortcuts_sequence/keyboard_shortcuts_sequence.tsx
@@ -0,0 +1,67 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+import {FormatXMLElementFn, PrimitiveType} from 'intl-messageformat';
+import React, {memo} from 'react';
+import {useIntl} from 'react-intl';
+
+import {ShortcutKeyVariant, ShortcutKey} from 'components/shortcut_key';
+import {isMac} from 'utils/utils';
+
+import {isMessageDescriptor, KeyboardShortcutDescriptor} from './keyboard_shortcuts';
+
+import './keyboard_shortcuts_sequence.scss';
+
+type Props = {
+ shortcut: KeyboardShortcutDescriptor;
+ values?: Record>;
+ hideDescription?: boolean;
+ hoistDescription?: boolean;
+ isInsideTooltip?: boolean;
+};
+
+function normalizeShortcutDescriptor(shortcut: KeyboardShortcutDescriptor) {
+ if (isMessageDescriptor(shortcut)) {
+ return shortcut;
+ }
+ const {default: standard, mac} = shortcut;
+ return isMac() && mac ? mac : standard;
+}
+
+const KEY_SEPARATOR = '|';
+
+function KeyboardShortcutSequence({shortcut, values, hideDescription, hoistDescription, isInsideTooltip}: Props) {
+ const {formatMessage} = useIntl();
+ const shortcutText = formatMessage(normalizeShortcutDescriptor(shortcut), values);
+ const splitShortcut = shortcutText.split('\t');
+
+ let description = '';
+ let keys = '';
+
+ if (splitShortcut.length > 1) {
+ description = splitShortcut[0];
+ keys = splitShortcut[1];
+ } else if (splitShortcut[0].includes(KEY_SEPARATOR)) {
+ keys = splitShortcut[0];
+ } else {
+ description = splitShortcut[0];
+ }
+
+ return (
+ <>
+ {hoistDescription && !hideDescription && description?.replace(/:{1,2}$/, '')}
+
+ {!hoistDescription && !hideDescription && description && {description}}
+ {keys?.split(KEY_SEPARATOR).map((key) => (
+
+ {key}
+
+ ))}
+
+ >
+ );
+}
+
+export default memo(KeyboardShortcutSequence);
diff --git a/components/search_shortcut/search_shortcut.tsx b/components/search_shortcut/search_shortcut.tsx
index 31fdb3779709..a7a2782bcca9 100644
--- a/components/search_shortcut/search_shortcut.tsx
+++ b/components/search_shortcut/search_shortcut.tsx
@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
-import {ShortcutKey, ShortcutKetVariant} from 'components/shortcut_key';
+import {ShortcutKey, ShortcutKeyVariant} from 'components/shortcut_key';
import {isMac} from 'utils/utils.jsx';
import {isDesktopApp} from 'utils/user_agent';
@@ -13,9 +13,9 @@ export const SearchShortcut = () => {
return (
- {controlKey}
- {!isDesktopApp() && {'Shift'}}
- {'F'}
+ {controlKey}
+ {!isDesktopApp() && {'Shift'}}
+ {'F'}
);
};
diff --git a/components/shortcut_key/index.ts b/components/shortcut_key/index.ts
index ddf42fff53b9..1b9505b2babf 100644
--- a/components/shortcut_key/index.ts
+++ b/components/shortcut_key/index.ts
@@ -1,5 +1,4 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {ShortcutKey, ShortcutKetVariant} from './shortcut_key';
-export {ShortcutKey, ShortcutKetVariant};
+export * from './shortcut_key';
diff --git a/components/shortcut_key/shortcut_key.scss b/components/shortcut_key/shortcut_key.scss
index 5499770b3bd4..f029bb35c299 100644
--- a/components/shortcut_key/shortcut_key.scss
+++ b/components/shortcut_key/shortcut_key.scss
@@ -12,5 +12,22 @@
background-color: rgba(var(--center-channel-color-rgb), 0.08);
color: var(--center-channel-color);
}
+
+ &.shortcut-key--tooltip {
+ padding: 2px 5px;
+ background-color: rgba(255, 255, 255, 0.08);
+ color: rgba(255, 255, 255, 0.72);
+ font-family: inherit;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: 16px;
+ }
+
+ &.shortcut-key--shortcut-modal {
+ font-family: inherit;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: 16px;
+ }
}
}
diff --git a/components/shortcut_key/shortcut_key.test.tsx b/components/shortcut_key/shortcut_key.test.tsx
index eb0c37a0284e..c6149b52f49c 100644
--- a/components/shortcut_key/shortcut_key.test.tsx
+++ b/components/shortcut_key/shortcut_key.test.tsx
@@ -3,7 +3,7 @@
import React from 'react';
import {shallow} from 'enzyme';
-import {ShortcutKey, ShortcutKetVariant} from './shortcut_key';
+import {ShortcutKey, ShortcutKeyVariant} from './shortcut_key';
describe('components/ShortcutKey', () => {
test('should match snapshot for regular key', () => {
@@ -12,7 +12,7 @@ describe('components/ShortcutKey', () => {
});
test('should match snapshot for contrast key', () => {
- const wrapper = shallow({'Shift'});
+ const wrapper = shallow({'Shift'});
expect(wrapper).toMatchSnapshot();
});
});
diff --git a/components/shortcut_key/shortcut_key.tsx b/components/shortcut_key/shortcut_key.tsx
index 3117066316e4..5bd1eaa5f452 100644
--- a/components/shortcut_key/shortcut_key.tsx
+++ b/components/shortcut_key/shortcut_key.tsx
@@ -1,26 +1,30 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
+import classNames from 'classnames';
import './shortcut_key.scss';
-export enum ShortcutKetVariant {
+export enum ShortcutKeyVariant {
Contrast = 'contrast',
+ Tooltip = 'tooltip',
+ ShortcutModal = 'shortcut',
}
export type ShortcutKeyProps = {
- variant?: ShortcutKetVariant;
+ variant?: ShortcutKeyVariant;
children: React.ReactNode;
}
-export const ShortcutKey = ({children, variant}: ShortcutKeyProps) => {
- let className = 'shortcut-key';
- if (variant === ShortcutKetVariant.Contrast) {
- className += ' shortcut-key--contrast';
- }
-
+export const ShortcutKey = ({children, variant}: ShortcutKeyProps): JSX.Element => {
return (
-
+
{children}
);
diff --git a/components/shortcuts_modal.jsx b/components/shortcuts_modal.jsx
deleted file mode 100644
index 7655b37c7511..000000000000
--- a/components/shortcuts_modal.jsx
+++ /dev/null
@@ -1,516 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-import PropTypes from 'prop-types';
-import React from 'react';
-import {Modal} from 'react-bootstrap';
-import {defineMessages, injectIntl} from 'react-intl';
-
-import ModalStore from 'stores/modal_store.jsx';
-import Constants from 'utils/constants';
-import {intlShape} from 'utils/react_intl';
-import {t} from 'utils/i18n';
-import * as Utils from 'utils/utils';
-
-const allShortcuts = defineMessages({
- mainHeader: {
- default: {
- id: t('shortcuts.header'),
- defaultMessage: 'Keyboard Shortcuts\tCtrl|/',
- },
- mac: {
- id: t('shortcuts.header.mac'),
- defaultMessage: 'Keyboard Shortcuts\t⌘|/',
- },
- },
- navHeader: {
- id: t('shortcuts.nav.header'),
- defaultMessage: 'Navigation',
- },
- navPrev: {
- default: {
- id: t('shortcuts.nav.prev'),
- defaultMessage: 'Previous channel:\tAlt|Up',
- },
- mac: {
- id: t('shortcuts.nav.prev.mac'),
- defaultMessage: 'Previous channel:\t⌥|Up',
- },
- },
- navNext: {
- default: {
- id: t('shortcuts.nav.next'),
- defaultMessage: 'Next channel:\tAlt|Down',
- },
- mac: {
- id: t('shortcuts.nav.next.mac'),
- defaultMessage: 'Next channel:\t⌥|Down',
- },
- },
- navUnreadPrev: {
- default: {
- id: t('shortcuts.nav.unread_prev'),
- defaultMessage: 'Previous unread channel:\tAlt|Shift|Up',
- },
- mac: {
- id: t('shortcuts.nav.unread_prev.mac'),
- defaultMessage: 'Previous unread channel:\t⌥|Shift|Up',
- },
- },
- navUnreadNext: {
- default: {
- id: t('shortcuts.nav.unread_next'),
- defaultMessage: 'Next unread channel:\tAlt|Shift|Down',
- },
- mac: {
- id: t('shortcuts.nav.unread_next.mac'),
- defaultMessage: 'Next unread channel:\t⌥|Shift|Down',
- },
- },
- teamNavPrev: {
- default: {
- id: t('shortcuts.team_nav.prev'),
- defaultMessage: 'Previous team:\tCtrl|Alt|Up',
- },
- mac: {
- id: t('shortcuts.team_nav.prev.mac'),
- defaultMessage: 'Previous team:\t⌘|⌥|Up',
- },
- },
- teamNavNext: {
- default: {
- id: t('shortcuts.team_nav.next'),
- defaultMessage: 'Next team:\tCtrl|Alt|Down',
- },
- mac: {
- id: t('shortcuts.team_nav.next.mac'),
- defaultMessage: 'Next team:\t⌘|⌥|Down',
- },
- },
- teamNavSwitcher: {
- default: {
- id: t('shortcuts.team_nav.switcher'),
- defaultMessage: 'Switch to a specific team:\tCtrl|Alt|[1-9]',
- },
- mac: {
- id: t('shortcuts.team_nav.switcher.mac'),
- defaultMessage: 'Switch to a specific team:\t⌘|⌥|[1-9]',
- },
- },
- navSwitcher: {
- default: {
- id: t('shortcuts.nav.switcher'),
- defaultMessage: 'Quick channel switcher:\tCtrl|K',
- },
- mac: {
- id: t('shortcuts.nav.switcher.mac'),
- defaultMessage: 'Quick channel switcher:\t⌘|K',
- },
- },
- navDMMenu: {
- default: {
- id: t('shortcuts.nav.direct_messages_menu'),
- defaultMessage: 'Direct messages menu:\tCtrl|Shift|K',
- },
- mac: {
- id: t('shortcuts.nav.direct_messages_menu.mac'),
- defaultMessage: 'Direct messages menu:\t⌘|Shift|K',
- },
- },
- navSettings: {
- default: {
- id: t('shortcuts.nav.settings'),
- defaultMessage: 'Account settings:\tCtrl|Shift|A',
- },
- mac: {
- id: t('shortcuts.nav.settings.mac'),
- defaultMessage: 'Account settings:\t⌘|Shift|A',
- },
- },
- navMentions: {
- default: {
- id: t('shortcuts.nav.recent_mentions'),
- defaultMessage: 'Recent mentions:\tCtrl|Shift|M',
- },
- mac: {
- id: t('shortcuts.nav.recent_mentions.mac'),
- defaultMessage: 'Recent mentions:\t⌘|Shift|M',
- },
- },
- navFocusCenter: {
- default: {
- id: t('shortcuts.nav.focus_center'),
- defaultMessage: 'Set focus to input field:\tCtrl|Shift|L',
- },
- mac: {
- id: t('shortcuts.nav.focus_center.mac'),
- defaultMessage: 'Set focus to input field:\t⌘|Shift|L',
- },
- },
- navOpenCloseSidebar: {
- default: {
- id: t('shortcuts.nav.open_close_sidebar'),
- defaultMessage: 'Open or close the right sidebar\tCtrl|.',
- },
- mac: {
- id: t('shortcuts.nav.open_close_sidebar.mac'),
- defaultMessage: 'Open or close the right sidebar\t⌘|.',
- },
- },
- msgHeader: {
- id: t('shortcuts.msgs.header'),
- defaultMessage: 'Messages',
- },
- msgInputHeader: {
- id: t('shortcuts.msgs.input.header'),
- defaultMessage: 'Works inside an empty input field',
- },
- msgEdit: {
- id: t('shortcuts.msgs.edit'),
- defaultMessage: 'Edit last message in channel:\tUp',
- },
- msgReply: {
- id: t('shortcuts.msgs.reply'),
- defaultMessage: 'Reply to last message in channel:\tShift|Up',
- },
- msgReprintPrev: {
- default: {
- id: t('shortcuts.msgs.reprint_prev'),
- defaultMessage: 'Reprint previous message:\tCtrl|Up',
- },
- mac: {
- id: t('shortcuts.msgs.reprint_prev.mac'),
- defaultMessage: 'Reprint previous message:\t⌘|Up',
- },
- },
- msgReprintNext: {
- default: {
- id: t('shortcuts.msgs.reprint_next'),
- defaultMessage: 'Reprint next message:\tCtrl|Down',
- },
- mac: {
- id: t('shortcuts.msgs.reprint_next.mac'),
- defaultMessage: 'Reprint next message:\t⌘|Down',
- },
- },
- msgCompHeader: {
- id: t('shortcuts.msgs.comp.header'),
- defaultMessage: 'Autocomplete',
- },
- msgCompUsername: {
- id: t('shortcuts.msgs.comp.username'),
- defaultMessage: 'Username:\t@|[a-z]|Tab',
- },
- msgCompChannel: {
- id: t('shortcuts.msgs.comp.channel'),
- defaultMessage: 'Channel:\t~|[a-z]|Tab',
- },
- msgCompEmoji: {
- id: t('shortcuts.msgs.comp.emoji'),
- defaultMessage: 'Emoji:\t:|[a-z]|Tab',
- },
- msgLastReaction: {
- default: {
- id: t('shortcuts.msgs.comp.last_reaction'),
- defaultMessage: 'React to last message:\tCtrl|Shift|\u29F5',
- },
- mac: {
- id: t('shortcuts.msgs.comp.last_reaction.mac'),
- defaultMessage: 'React to last message:\t⌘|Shift|\u29F5',
- },
- },
- msgMarkdownHeader: {
- id: t('shortcuts.msgs.markdown.header'),
- defaultMessage: 'Formatting',
- },
- msgMarkdownBold: {
- default: {
- id: t('shortcuts.msgs.markdown.bold'),
- defaultMessage: 'Bold:\tCtrl|B',
- },
- mac: {
- id: t('shortcuts.msgs.markdown.bold.mac'),
- defaultMessage: 'Bold:\t⌘|B',
- },
- },
- msgMarkdownItalic: {
- default: {
- id: t('shortcuts.msgs.markdown.italic'),
- defaultMessage: 'Italic:\tCtrl|I',
- },
- mac: {
- id: t('shortcuts.msgs.markdown.italic.mac'),
- defaultMessage: 'Italic:\t⌘|I',
- },
- },
- msgMarkdownLink: {
- default: {
- id: t('shortcuts.msgs.markdown.link'),
- defaultMessage: 'Link:\tCtrl|Alt|K',
- },
- mac: {
- id: t('shortcuts.msgs.markdown.link.mac'),
- defaultMessage: 'Link:\t⌘|Alt|K',
- },
- },
- filesHeader: {
- id: t('shortcuts.files.header'),
- defaultMessage: 'Files',
- },
- filesUpload: {
- default: {
- id: t('shortcuts.files.upload'),
- defaultMessage: 'Upload files:\tCtrl|U',
- },
- mac: {
- id: t('shortcuts.files.upload.mac'),
- defaultMessage: 'Upload files:\t⌘|U',
- },
- },
- browserHeader: {
- id: t('shortcuts.browser.header'),
- defaultMessage: 'Built-in Browser Commands',
- },
- browserChannelPrev: {
- default: {
- id: t('shortcuts.browser.channel_prev'),
- defaultMessage: 'Back in history:\tAlt|Left',
- },
- mac: {
- id: t('shortcuts.browser.channel_prev.mac'),
- defaultMessage: 'Back in history:\t⌘|[',
- },
- },
- browserChannelNext: {
- default: {
- id: t('shortcuts.browser.channel_next'),
- defaultMessage: 'Forward in history:\tAlt|Right',
- },
- mac: {
- id: t('shortcuts.browser.channel_next.mac'),
- defaultMessage: 'Forward in history:\t⌘|]',
- },
- },
- browserFontIncrease: {
- default: {
- id: t('shortcuts.browser.font_increase'),
- defaultMessage: 'Zoom in:\tCtrl|+',
- },
- mac: {
- id: t('shortcuts.browser.font_increase.mac'),
- defaultMessage: 'Zoom in:\t⌘|+',
- },
- },
- browserFontDecrease: {
- default: {
- id: t('shortcuts.browser.font_decrease'),
- defaultMessage: 'Zoom out:\tCtrl|-',
- },
- mac: {
- id: t('shortcuts.browser.font_decrease.mac'),
- defaultMessage: 'Zoom out:\t⌘|-',
- },
- },
- browserInputHeader: {
- id: t('shortcuts.browser.input.header'),
- defaultMessage: 'Works inside an input field',
- },
- browserHighlightPrev: {
- id: t('shortcuts.browser.highlight_prev'),
- defaultMessage: 'Highlight text to the previous line:\tShift|Up',
- },
- browserHighlightNext: {
- id: t('shortcuts.browser.highlight_next'),
- defaultMessage: 'Highlight text to the next line:\tShift|Down',
- },
- browserNewline: {
- id: t('shortcuts.browser.newline'),
- defaultMessage: 'Create a new line:\tShift|Enter',
- },
- info: {
- id: t('shortcuts.info'),
- defaultMessage: 'Begin a message with / for a list of all the commands at your disposal.',
- },
-});
-
-class ShortcutsModal extends React.PureComponent {
- static propTypes = {
- intl: intlShape.isRequired,
- isMac: PropTypes.bool.isRequired,
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- show: false,
- };
- }
-
- componentDidMount() {
- ModalStore.addModalListener(Constants.ActionTypes.TOGGLE_SHORTCUTS_MODAL, this.handleToggle);
- }
-
- componentWillUnmount() {
- ModalStore.removeModalListener(Constants.ActionTypes.TOGGLE_SHORTCUTS_MODAL, this.handleToggle);
- }
-
- handleToggle = () => {
- //toggles the state of shortcut dialog
- this.setState({
- show: !this.state.show,
- });
- }
-
- handleHide = () => {
- this.setState({show: false});
- }
-
- getShortcuts() {
- const {isMac} = this.props;
- const shortcuts = {};
- Object.keys(allShortcuts).forEach((s) => {
- if (isMac && allShortcuts[s].mac) {
- shortcuts[s] = allShortcuts[s].mac;
- } else if (!isMac && allShortcuts[s].default) {
- shortcuts[s] = allShortcuts[s].default;
- } else {
- shortcuts[s] = allShortcuts[s];
- }
- });
-
- return shortcuts;
- }
-
- render() {
- const shortcuts = this.getShortcuts();
- const {formatMessage} = this.props.intl;
-
- const isLinux = Utils.isLinux();
-
- return (
-
-
-
-
- {renderShortcut(formatMessage(shortcuts.mainHeader))}
-
-
-
-
-
-
-
-
{formatMessage(shortcuts.navHeader)}
- {renderShortcut(formatMessage(shortcuts.navPrev))}
- {renderShortcut(formatMessage(shortcuts.navNext))}
- {renderShortcut(formatMessage(shortcuts.navUnreadPrev))}
- {renderShortcut(formatMessage(shortcuts.navUnreadNext))}
- {!isLinux && renderShortcut(formatMessage(shortcuts.teamNavPrev))}
- {!isLinux && renderShortcut(formatMessage(shortcuts.teamNavNext))}
- {renderShortcut(formatMessage(shortcuts.teamNavSwitcher))}
- {renderShortcut(formatMessage(shortcuts.navSwitcher))}
- {renderShortcut(formatMessage(shortcuts.navDMMenu))}
- {renderShortcut(formatMessage(shortcuts.navSettings))}
- {renderShortcut(formatMessage(shortcuts.navMentions))}
- {renderShortcut(formatMessage(shortcuts.navFocusCenter))}
- {renderShortcut(formatMessage(shortcuts.navOpenCloseSidebar))}
-
-
-
-
-
-
-
{formatMessage(shortcuts.msgHeader)}
-
{formatMessage(shortcuts.msgInputHeader)}
-
- {renderShortcut(formatMessage(shortcuts.msgEdit))}
- {renderShortcut(formatMessage(shortcuts.msgReply))}
- {renderShortcut(formatMessage(shortcuts.msgLastReaction))}
- {renderShortcut(formatMessage(shortcuts.msgReprintPrev))}
- {renderShortcut(formatMessage(shortcuts.msgReprintNext))}
-
-
{formatMessage(shortcuts.msgCompHeader)}
-
- {renderShortcut(formatMessage(shortcuts.msgCompUsername))}
- {renderShortcut(formatMessage(shortcuts.msgCompChannel))}
- {renderShortcut(formatMessage(shortcuts.msgCompEmoji))}
-
-
{formatMessage(shortcuts.msgMarkdownHeader)}
-
- {renderShortcut(formatMessage(shortcuts.msgMarkdownBold))}
- {renderShortcut(formatMessage(shortcuts.msgMarkdownItalic))}
- {renderShortcut(formatMessage(shortcuts.msgMarkdownLink))}
-
-
-
-
-
-
-
-
{formatMessage(shortcuts.filesHeader)}
- {renderShortcut(formatMessage(shortcuts.filesUpload))}
-
-
-
{formatMessage(shortcuts.browserHeader)}
- {renderShortcut(formatMessage(shortcuts.browserChannelPrev))}
- {renderShortcut(formatMessage(shortcuts.browserChannelNext))}
- {renderShortcut(formatMessage(shortcuts.browserFontIncrease))}
- {renderShortcut(formatMessage(shortcuts.browserFontDecrease))}
-
{formatMessage(shortcuts.browserInputHeader)}
-
- {renderShortcut(formatMessage(shortcuts.browserHighlightPrev))}
- {renderShortcut(formatMessage(shortcuts.browserHighlightNext))}
- {renderShortcut(formatMessage(shortcuts.browserNewline))}
-
-
-
-
-
- {formatMessage(shortcuts.info)}
-
-
-
- );
- }
-}
-
-function renderShortcut(text) {
- if (!text) {
- return null;
- }
-
- const shortcut = text.split('\t');
- const description = {shortcut[0]};
-
- let keys = null;
- if (shortcut.length > 1) {
- keys = shortcut[1].split('|').map((key) => (
-
- {key}
-
- ));
- }
-
- return (
-
- {description}
- {keys}
-
- );
-}
-
-export default injectIntl(ShortcutsModal);
diff --git a/components/shortcuts_modal.test.jsx b/components/shortcuts_modal.test.jsx
deleted file mode 100644
index 954c58387754..000000000000
--- a/components/shortcuts_modal.test.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-import React from 'react';
-
-import {mountWithIntl} from 'tests/helpers/intl-test-helper';
-import ShortcutsModal from 'components/shortcuts_modal.jsx';
-
-describe('components/ShortcutsModal', () => {
- test('should match snapshot modal for Mac', () => {
- const wrapper = mountWithIntl(
- ,
- );
-
- expect(wrapper).toMatchSnapshot();
- });
-
- test('should match snapshot modal for non-Mac like Windows/Linux', () => {
- const wrapper = mountWithIntl(
- ,
- );
-
- expect(wrapper).toMatchSnapshot();
- });
-});
diff --git a/components/sidebar/channel_navigator/channel_navigator.tsx b/components/sidebar/channel_navigator/channel_navigator.tsx
index 66fef9f9ae00..83f1c6a717e2 100644
--- a/components/sidebar/channel_navigator/channel_navigator.tsx
+++ b/components/sidebar/channel_navigator/channel_navigator.tsx
@@ -4,6 +4,7 @@
import React from 'react';
import {FormattedMessage} from 'react-intl';
import classNames from 'classnames';
+import {Tooltip} from 'react-bootstrap';
import {trackEvent} from 'actions/telemetry_actions';
import Constants, {ModalIdentifiers} from 'utils/constants';
@@ -13,6 +14,11 @@ import {isDesktopApp} from 'utils/user_agent';
import AddChannelDropdown from '../add_channel_dropdown';
import ChannelFilter from '../channel_filter';
import {AddChannelButtonTreatments} from 'mattermost-redux/constants/config';
+import KeyboardShortcutSequence, {
+ KEYBOARD_SHORTCUTS,
+ KeyboardShortcutDescriptor,
+} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
+import OverlayTrigger from 'components/overlay_trigger';
export type Props = {
addChannelButton?: AddChannelButtonTreatments;
@@ -146,27 +152,52 @@ export default class ChannelNavigator extends React.PureComponent {
/>
);
}
+ const getTooltip = (shortcut: KeyboardShortcutDescriptor) => (
+
+
+
+ );
let layout;
if (isDesktopApp() && !this.props.globalHeaderEnabled) {
const historyArrows = (
<>
-
-
+
+
-
-
+
+
>
);
diff --git a/components/sidebar/sidebar_category/__snapshots__/sidebar_category.test.tsx.snap b/components/sidebar/sidebar_category/__snapshots__/sidebar_category.test.tsx.snap
index 24e9f32ba8d9..8c04cfa03f5e 100644
--- a/components/sidebar/sidebar_category/__snapshots__/sidebar_category.test.tsx.snap
+++ b/components/sidebar/sidebar_category/__snapshots__/sidebar_category.test.tsx.snap
@@ -316,6 +316,22 @@ exports[`components/sidebar/sidebar_category should match snapshot when sorting
placement="right"
>
Create new direct message
+
}
placement="top"
@@ -426,6 +442,22 @@ exports[`components/sidebar/sidebar_category should match snapshot when the cate
placement="right"
>
Create new direct message
+
}
placement="top"
diff --git a/components/sidebar/sidebar_category/sidebar_category.tsx b/components/sidebar/sidebar_category/sidebar_category.tsx
index adde4fbc69c3..9f7fbe519c0f 100644
--- a/components/sidebar/sidebar_category/sidebar_category.tsx
+++ b/components/sidebar/sidebar_category/sidebar_category.tsx
@@ -10,23 +10,20 @@ import classNames from 'classnames';
import {CategoryTypes} from 'mattermost-redux/constants/channel_categories';
import {ChannelCategory, CategorySorting} from 'mattermost-redux/types/channel_categories';
import {localizeMessage} from 'mattermost-redux/utils/i18n_utils';
-
import {trackEvent} from 'actions/telemetry_actions';
-
import OverlayTrigger from 'components/overlay_trigger';
-
import {DraggingState} from 'types/store';
-
import Constants, {A11yCustomEventTypes, DraggingStateTypes, DraggingStates} from 'utils/constants';
import {t} from 'utils/i18n';
import {isKeyPressed} from 'utils/utils';
-
import SidebarChannel from '../sidebar_channel';
import {SidebarCategoryHeader} from '../sidebar_category_header';
import InviteMembersButton from '../invite_members_button';
+import KeyboardShortcutSequence, {
+ KEYBOARD_SHORTCUTS,
+} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
import SidebarCategorySortingMenu from './sidebar_category_sorting_menu';
-
import SidebarCategoryMenu from './sidebar_category_menu';
type Props = {
@@ -283,6 +280,11 @@ export default class SidebarCategory extends React.PureComponent {
className='hidden-xs'
>
{addHelpLabel}
+
);
diff --git a/components/team_sidebar/components/team_button.tsx b/components/team_sidebar/components/team_button.tsx
index 8c2a5e7c402c..443bbfd2ab7b 100644
--- a/components/team_sidebar/components/team_button.tsx
+++ b/components/team_sidebar/components/team_button.tsx
@@ -11,10 +11,13 @@ import classNames from 'classnames';
import {mark, trackEvent} from 'actions/telemetry_actions.jsx';
import Constants from 'utils/constants';
import {isDesktopApp} from 'utils/user_agent';
-import {isMac, localizeMessage} from 'utils/utils.jsx';
+import {localizeMessage} from 'utils/utils.jsx';
import CopyUrlContextMenu from 'components/copy_url_context_menu';
import OverlayTrigger from 'components/overlay_trigger';
import TeamIcon from '../../widgets/team_icon/team_icon';
+import KeyboardShortcutSequence, {
+ KEYBOARD_SHORTCUTS,
+} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
interface Props {
btnClass?: string;
@@ -51,7 +54,7 @@ class TeamButton extends React.PureComponent {
}
render() {
- const {teamIconUrl, displayName, btnClass, mentions, unread, isDraggable = false, teamIndex, teamId} = this.props;
+ const {teamIconUrl, displayName, btnClass, mentions, unread, isDraggable = false, teamIndex, teamId, order} = this.props;
const {formatMessage} = this.props.intl;
let teamClass: string = this.props.active ? 'active' : '';
@@ -119,36 +122,22 @@ class TeamButton extends React.PureComponent {
let toolTip = this.props.tip || localizeMessage('team.button.name_undefined', 'This team does not have a name');
let orderIndicator: JSX.Element | undefined;
if (typeof this.props.order !== 'undefined' && this.props.order < 10) {
- let toolTipHelp;
- if (isMac()) {
- toolTipHelp = formatMessage({
- id: 'team.button.tooltip.mac',
- defaultMessage: '⌘ ⌥ {order}',
- },
- {
- order: this.props.order,
- });
- } else {
- toolTipHelp = formatMessage({
- id: 'team.button.tooltip',
- defaultMessage: 'Ctrl+Alt+{order}',
- },
- {
- order: this.props.order,
- });
- }
-
toolTip = (
<>
{toolTip}
- {toolTipHelp}
+
>
);
if (this.props.showOrder) {
orderIndicator = (
- {this.props.order}
+ {order}
);
}
diff --git a/i18n/en.json b/i18n/en.json
index 70633105c13b..ae6a96d34da5 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -4298,8 +4298,8 @@
"team.button.ariaLabel": "{teamName} team",
"team.button.mentions.ariaLabel": "{teamName} team, {mentionCount} mentions",
"team.button.name_undefined": "This team does not have a name",
- "team.button.tooltip": "Ctrl+Alt+{order}",
- "team.button.tooltip.mac": "⌘ ⌥ {order}",
+ "team.button.tooltip": "Ctrl|Alt|{order}",
+ "team.button.tooltip.mac": "⌘|⌥|{order}",
"team.button.unread.ariaLabel": "{teamName} team unread",
"terms_of_service.agreeButton": "I Agree",
"terms_of_service.api_error": "Unable to complete the request. If this issue persists, contact your System Administrator.",
diff --git a/sass/components/_tooltip.scss b/sass/components/_tooltip.scss
index 5e15e392e468..9da25f16ce94 100644
--- a/sass/components/_tooltip.scss
+++ b/sass/components/_tooltip.scss
@@ -2,15 +2,16 @@
.tooltip {
max-width: 220px;
+ font-family: inherit;
pointer-events: none;
word-wrap: break-word;
.tooltip-inner {
max-width: 100%;
- padding: 5px 10px 6px;
+ padding: 4px 8px;
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.12);
- font-size: 13px;
- font-weight: 500;
+ font-size: 12px;
+ font-weight: 600;
line-height: 18px;
text-align: center;
word-break: break-word;
diff --git a/sass/routes/_module.scss b/sass/routes/_module.scss
index b7ecc08e78c5..c0a5b19bca0e 100644
--- a/sass/routes/_module.scss
+++ b/sass/routes/_module.scss
@@ -11,6 +11,5 @@
@import 'loading';
@import 'print';
@import 'settings';
-@import 'shortcuts-modal';
@import 'signup';
@import 'statistics';