Add Keyboard shortcuts dialog
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
fac4561ac8
commit
cad28c81c0
10 changed files with 444 additions and 6 deletions
|
@ -118,6 +118,7 @@
|
||||||
"@babel/preset-typescript": "^7.7.4",
|
"@babel/preset-typescript": "^7.7.4",
|
||||||
"@babel/register": "^7.7.4",
|
"@babel/register": "^7.7.4",
|
||||||
"@peculiar/webcrypto": "^1.0.22",
|
"@peculiar/webcrypto": "^1.0.22",
|
||||||
|
"@types/classnames": "^2.2.10",
|
||||||
"@types/react": "16.9",
|
"@types/react": "16.9",
|
||||||
"babel-eslint": "^10.0.3",
|
"babel-eslint": "^10.0.3",
|
||||||
"babel-jest": "^24.9.0",
|
"babel-jest": "^24.9.0",
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
@import "./views/dialogs/_GroupAddressPicker.scss";
|
@import "./views/dialogs/_GroupAddressPicker.scss";
|
||||||
@import "./views/dialogs/_IncomingSasDialog.scss";
|
@import "./views/dialogs/_IncomingSasDialog.scss";
|
||||||
@import "./views/dialogs/_InviteDialog.scss";
|
@import "./views/dialogs/_InviteDialog.scss";
|
||||||
|
@import "./views/dialogs/_KeyboardShortcutsDialog.scss";
|
||||||
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
|
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
|
||||||
@import "./views/dialogs/_NewSessionReviewDialog.scss";
|
@import "./views/dialogs/_NewSessionReviewDialog.scss";
|
||||||
@import "./views/dialogs/_RoomSettingsDialog.scss";
|
@import "./views/dialogs/_RoomSettingsDialog.scss";
|
||||||
|
|
65
res/css/views/dialogs/_KeyboardShortcutsDialog.scss
Normal file
65
res/css/views/dialogs/_KeyboardShortcutsDialog.scss
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.mx_KeyboardShortcutsDialog {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: -50px;
|
||||||
|
max-height: 700px; // XXX: this may need adjusting when adding new shortcuts
|
||||||
|
|
||||||
|
.mx_KeyboardShortcutsDialog_category {
|
||||||
|
width: 33.3333%; // 3 columns
|
||||||
|
margin: 0 0 40px;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
margin: 15px 0 5px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: $roomheader-addroom-bg-color;
|
||||||
|
margin-right: 5px;
|
||||||
|
min-width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid black;
|
||||||
|
box-shadow: 0 2px black;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
text-transform: capitalize;
|
||||||
|
|
||||||
|
& + kbd {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_KeyboardShortcutsDialog_inline div {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,7 @@ export const Key = {
|
||||||
GREATER_THAN: ">",
|
GREATER_THAN: ">",
|
||||||
BACKTICK: "`",
|
BACKTICK: "`",
|
||||||
SPACE: " ",
|
SPACE: " ",
|
||||||
|
SLASH: "/",
|
||||||
A: "a",
|
A: "a",
|
||||||
B: "b",
|
B: "b",
|
||||||
C: "c",
|
C: "c",
|
||||||
|
@ -68,8 +69,9 @@ export const Key = {
|
||||||
Z: "z",
|
Z: "z",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||||
|
|
||||||
export function isOnlyCtrlOrCmdKeyEvent(ev) {
|
export function isOnlyCtrlOrCmdKeyEvent(ev) {
|
||||||
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
|
||||||
if (isMac) {
|
if (isMac) {
|
||||||
return ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
|
return ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
|
||||||
} else {
|
} else {
|
||||||
|
@ -78,7 +80,6 @@ export function isOnlyCtrlOrCmdKeyEvent(ev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isOnlyCtrlOrCmdIgnoreShiftKeyEvent(ev) {
|
export function isOnlyCtrlOrCmdIgnoreShiftKeyEvent(ev) {
|
||||||
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
|
||||||
if (isMac) {
|
if (isMac) {
|
||||||
return ev.metaKey && !ev.altKey && !ev.ctrlKey;
|
return ev.metaKey && !ev.altKey && !ev.ctrlKey;
|
||||||
} else {
|
} else {
|
313
src/accessibility/KeyboardShortcuts.tsx
Normal file
313
src/accessibility/KeyboardShortcuts.tsx
Normal file
|
@ -0,0 +1,313 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
import * as sdk from "../index";
|
||||||
|
import Modal from "../Modal";
|
||||||
|
import { _t, _td } from "../languageHandler";
|
||||||
|
import {isMac, Key} from "../Keyboard";
|
||||||
|
|
||||||
|
// TS: once languageHandler is TS we can probably inline this into the enum
|
||||||
|
_td("Navigation");
|
||||||
|
_td("Calls");
|
||||||
|
_td("Composer");
|
||||||
|
_td("Room List");
|
||||||
|
_td("Autocomplete");
|
||||||
|
|
||||||
|
export enum Categories {
|
||||||
|
NAVIGATION="Navigation",
|
||||||
|
CALLS="Calls",
|
||||||
|
COMPOSER="Composer",
|
||||||
|
ROOM_LIST="Room List",
|
||||||
|
AUTOCOMPLETE="Autocomplete",
|
||||||
|
}
|
||||||
|
|
||||||
|
// TS: once languageHandler is TS we can probably inline this into the enum
|
||||||
|
_td("Alt");
|
||||||
|
_td("Alt Gr");
|
||||||
|
_td("Shift");
|
||||||
|
_td("Super");
|
||||||
|
_td("Ctrl");
|
||||||
|
|
||||||
|
export enum Modifiers {
|
||||||
|
ALT="Alt",
|
||||||
|
OPTION="Option", // This gets displayed as an Icon
|
||||||
|
ALT_GR="Alt Gr",
|
||||||
|
SHIFT="Shift",
|
||||||
|
SUPER="Super", // should this be "Windows"?
|
||||||
|
// Instead of using below, consider CMD_OR_CTRL
|
||||||
|
COMMAND="Command", // This gets displayed as an Icon
|
||||||
|
CONTROL="Ctrl",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meta-modifier: isMac ? CMD : CONTROL
|
||||||
|
export const CMD_OR_CTRL = isMac ? Modifiers.COMMAND : Modifiers.CONTROL;
|
||||||
|
|
||||||
|
interface IKeybind {
|
||||||
|
modifiers?: Modifiers[];
|
||||||
|
key: string; // TS: fix this once Key is an enum
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IShortcut {
|
||||||
|
keybinds: IKeybind[];
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shortcuts: Record<Categories, IShortcut[]> = {
|
||||||
|
[Categories.COMPOSER]: [
|
||||||
|
{
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.B,
|
||||||
|
}],
|
||||||
|
description: _td("Toggle Bold"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.I,
|
||||||
|
}],
|
||||||
|
description: _td("Toggle Italics"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.GREATER_THAN,
|
||||||
|
}],
|
||||||
|
description: _td("Toggle Quote"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.M,
|
||||||
|
}],
|
||||||
|
description: _td("Toggle Markdown"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [Modifiers.SHIFT],
|
||||||
|
key: Key.ENTER,
|
||||||
|
}],
|
||||||
|
description: _td("New line"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ARROW_UP,
|
||||||
|
}, {
|
||||||
|
key: Key.ARROW_DOWN,
|
||||||
|
}],
|
||||||
|
description: _td("Navigate recent messages to edit"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.HOME,
|
||||||
|
}, {
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.END,
|
||||||
|
}],
|
||||||
|
description: _td("Jump to start/end of the composer"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
[Categories.CALLS]: [
|
||||||
|
{
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.D,
|
||||||
|
}],
|
||||||
|
description: _td("Toggle microphone mute"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.E,
|
||||||
|
}],
|
||||||
|
description: _td("Toggle video on/off"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
[Categories.ROOM_LIST]: [
|
||||||
|
{
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.K,
|
||||||
|
}],
|
||||||
|
description: _td("Jump to room search"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ARROW_UP,
|
||||||
|
}, {
|
||||||
|
key: Key.ARROW_DOWN,
|
||||||
|
}],
|
||||||
|
description: _td("Navigate up/down in the room list"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ENTER,
|
||||||
|
}],
|
||||||
|
description: _td("Select room from the room list"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ARROW_LEFT,
|
||||||
|
}],
|
||||||
|
description: _td("Collapse room list section"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ARROW_RIGHT,
|
||||||
|
}],
|
||||||
|
description: _td("Expand room list section"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ESCAPE,
|
||||||
|
}],
|
||||||
|
description: _td("Clear room list filter field"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
[Categories.NAVIGATION]: [
|
||||||
|
{
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.PAGE_UP,
|
||||||
|
}, {
|
||||||
|
key: Key.PAGE_DOWN,
|
||||||
|
}],
|
||||||
|
description: _td("Scroll up/down in the timeline"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.BACKTICK,
|
||||||
|
}],
|
||||||
|
description: _td("Toggle the top left menu"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ESCAPE,
|
||||||
|
}],
|
||||||
|
description: _td("Close dialog or context menu"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ENTER,
|
||||||
|
}, {
|
||||||
|
key: Key.SPACE,
|
||||||
|
}],
|
||||||
|
description: _td("Activate selected button"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
modifiers: [CMD_OR_CTRL],
|
||||||
|
key: Key.SLASH,
|
||||||
|
}],
|
||||||
|
description: _td("Toggle this dialog"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
[Categories.AUTOCOMPLETE]: [
|
||||||
|
{
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ARROW_UP,
|
||||||
|
}, {
|
||||||
|
key: Key.ARROW_DOWN,
|
||||||
|
}],
|
||||||
|
description: _td("Move autocomplete selection up/down"),
|
||||||
|
}, {
|
||||||
|
keybinds: [{
|
||||||
|
key: Key.ESCAPE,
|
||||||
|
}],
|
||||||
|
description: _td("Cancel autocomplete"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IModal {
|
||||||
|
close: () => void;
|
||||||
|
finished: Promise<any[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const modifierIcon: Record<Modifiers, string> = {
|
||||||
|
[Modifiers.COMMAND]: "⌘",
|
||||||
|
[Modifiers.OPTION]: "⌥",
|
||||||
|
};
|
||||||
|
|
||||||
|
const alternateKeyName: Record<string, string> = { // TS: fix this once Key is an enum
|
||||||
|
[Key.PAGE_UP]: _td("Page Up"),
|
||||||
|
[Key.PAGE_DOWN]: _td("Page Down"),
|
||||||
|
[Key.ESCAPE]: _td("Esc"),
|
||||||
|
[Key.ENTER]: _td("Enter"),
|
||||||
|
[Key.SPACE]: _td("Space"),
|
||||||
|
[Key.HOME]: _td("Home"),
|
||||||
|
[Key.END]: _td("End"),
|
||||||
|
};
|
||||||
|
const keyIcon: Record<string, string> = { // TS: fix this once Key is an enum
|
||||||
|
[Key.ARROW_UP]: "↑",
|
||||||
|
[Key.ARROW_DOWN]: "↓",
|
||||||
|
[Key.ARROW_LEFT]: "←",
|
||||||
|
[Key.ARROW_RIGHT]: "→",
|
||||||
|
};
|
||||||
|
|
||||||
|
const Shortcut: React.FC<{
|
||||||
|
shortcut: IShortcut;
|
||||||
|
}> = ({shortcut}) => {
|
||||||
|
const classes = classNames({
|
||||||
|
"mx_KeyboardShortcutsDialog_inline": shortcut.keybinds.every(k => !k.modifiers || k.modifiers.length === 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
return <div className={classes}>
|
||||||
|
<h5>{ _t(shortcut.description) }</h5>
|
||||||
|
{ shortcut.keybinds.map(s => {
|
||||||
|
let text = s.key;
|
||||||
|
if (alternateKeyName[s.key]) {
|
||||||
|
text = _t(alternateKeyName[s.key]);
|
||||||
|
} else if (keyIcon[s.key]) {
|
||||||
|
text = keyIcon[s.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div key={s.key}>
|
||||||
|
{ s.modifiers && s.modifiers.map(m => {
|
||||||
|
return <React.Fragment key={m}>
|
||||||
|
<kbd>{ modifierIcon[m] || _t(m) }</kbd>+
|
||||||
|
</React.Fragment>;
|
||||||
|
}) }
|
||||||
|
<kbd>{ text }</kbd>
|
||||||
|
</div>;
|
||||||
|
}) }
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
let activeModal: IModal = null;
|
||||||
|
export const toggleDialog = () => {
|
||||||
|
if (activeModal) {
|
||||||
|
activeModal.close();
|
||||||
|
activeModal = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sections = Object.entries(shortcuts).map(([category, list]) => {
|
||||||
|
return <div className="mx_KeyboardShortcutsDialog_category" key={category}>
|
||||||
|
<h3>{_t(category)}</h3>
|
||||||
|
<div>{list.map(shortcut => <Shortcut key={shortcut.description} shortcut={shortcut} />)}</div>
|
||||||
|
</div>;
|
||||||
|
});
|
||||||
|
|
||||||
|
const InfoDialog = sdk.getComponent('dialogs.InfoDialog');
|
||||||
|
activeModal = Modal.createTrackedDialog("Keyboard Shortcuts", "", InfoDialog, {
|
||||||
|
className: "mx_KeyboardShortcutsDialog",
|
||||||
|
title: _t("Keyboard Shortcuts"),
|
||||||
|
description: sections,
|
||||||
|
hasCloseButton: true,
|
||||||
|
onKeyDown: (ev) => {
|
||||||
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && ev.key === Key.SLASH) { // Ctrl + /
|
||||||
|
ev.stopPropagation();
|
||||||
|
activeModal.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFinished: () => {
|
||||||
|
activeModal = null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
|
@ -39,6 +39,7 @@ import RoomListActions from '../../actions/RoomListActions';
|
||||||
import ResizeHandle from '../views/elements/ResizeHandle';
|
import ResizeHandle from '../views/elements/ResizeHandle';
|
||||||
import {Resizer, CollapseDistributor} from '../../resizer';
|
import {Resizer, CollapseDistributor} from '../../resizer';
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
|
import * as KeyboardShortcuts from "../../accessibility/KeyboardShortcuts";
|
||||||
// We need to fetch each pinned message individually (if we don't already have it)
|
// We need to fetch each pinned message individually (if we don't already have it)
|
||||||
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
||||||
// NB. this is just for server notices rather than pinned messages in general.
|
// NB. this is just for server notices rather than pinned messages in general.
|
||||||
|
@ -365,8 +366,6 @@ const LoggedInView = createReactClass({
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Key.BACKTICK:
|
case Key.BACKTICK:
|
||||||
if (ev.key !== "`") break;
|
|
||||||
|
|
||||||
// Ideally this would be CTRL+P for "Profile", but that's
|
// Ideally this would be CTRL+P for "Profile", but that's
|
||||||
// taken by the print dialog. CTRL+I for "Information"
|
// taken by the print dialog. CTRL+I for "Information"
|
||||||
// was previously chosen but conflicted with italics in
|
// was previously chosen but conflicted with italics in
|
||||||
|
@ -379,6 +378,13 @@ const LoggedInView = createReactClass({
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Key.SLASH:
|
||||||
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
|
KeyboardShortcuts.toggleDialog();
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handled) {
|
if (handled) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ export default createReactClass({
|
||||||
button: PropTypes.string,
|
button: PropTypes.string,
|
||||||
onFinished: PropTypes.func,
|
onFinished: PropTypes.func,
|
||||||
hasCloseButton: PropTypes.bool,
|
hasCloseButton: PropTypes.bool,
|
||||||
|
onKeyDown: PropTypes.func,
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps: function() {
|
getDefaultProps: function() {
|
||||||
|
@ -50,10 +51,13 @@ export default createReactClass({
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return (
|
return (
|
||||||
<BaseDialog className="mx_InfoDialog" onFinished={this.props.onFinished}
|
<BaseDialog
|
||||||
|
className="mx_InfoDialog"
|
||||||
|
onFinished={this.props.onFinished}
|
||||||
title={this.props.title}
|
title={this.props.title}
|
||||||
contentId='mx_Dialog_content'
|
contentId='mx_Dialog_content'
|
||||||
hasCancel={this.props.hasCloseButton}
|
hasCancel={this.props.hasCloseButton}
|
||||||
|
onKeyDown={this.props.onKeyDown}
|
||||||
>
|
>
|
||||||
<div className={classNames("mx_Dialog_content", this.props.className)} id="mx_Dialog_content">
|
<div className={classNames("mx_Dialog_content", this.props.className)} id="mx_Dialog_content">
|
||||||
{ this.props.description }
|
{ this.props.description }
|
||||||
|
|
|
@ -24,6 +24,7 @@ import createRoom from "../../../../../createRoom";
|
||||||
import Modal from "../../../../../Modal";
|
import Modal from "../../../../../Modal";
|
||||||
import * as sdk from "../../../../../";
|
import * as sdk from "../../../../../";
|
||||||
import PlatformPeg from "../../../../../PlatformPeg";
|
import PlatformPeg from "../../../../../PlatformPeg";
|
||||||
|
import * as KeyboardShortcuts from "../../../../../accessibility/KeyboardShortcuts";
|
||||||
|
|
||||||
export default class HelpUserSettingsTab extends React.Component {
|
export default class HelpUserSettingsTab extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -224,6 +225,9 @@ export default class HelpUserSettingsTab extends React.Component {
|
||||||
<div className='mx_SettingsTab_subsectionText'>
|
<div className='mx_SettingsTab_subsectionText'>
|
||||||
{faqText}
|
{faqText}
|
||||||
</div>
|
</div>
|
||||||
|
<AccessibleButton kind="primary" onClick={KeyboardShortcuts.toggleDialog}>
|
||||||
|
{ _t("Keyboard Shortcuts") }
|
||||||
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
<div className='mx_SettingsTab_section mx_HelpUserSettingsTab_versions'>
|
<div className='mx_SettingsTab_section mx_HelpUserSettingsTab_versions'>
|
||||||
<span className='mx_SettingsTab_subheading'>{_t("Versions")}</span>
|
<span className='mx_SettingsTab_subheading'>{_t("Versions")}</span>
|
||||||
|
|
|
@ -742,6 +742,7 @@
|
||||||
"Clear cache and reload": "Clear cache and reload",
|
"Clear cache and reload": "Clear cache and reload",
|
||||||
"To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.": "To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.",
|
"To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.": "To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.",
|
||||||
"FAQ": "FAQ",
|
"FAQ": "FAQ",
|
||||||
|
"Keyboard Shortcuts": "Keyboard Shortcuts",
|
||||||
"Versions": "Versions",
|
"Versions": "Versions",
|
||||||
"riot-web version:": "riot-web version:",
|
"riot-web version:": "riot-web version:",
|
||||||
"olm version:": "olm version:",
|
"olm version:": "olm version:",
|
||||||
|
@ -2155,5 +2156,42 @@
|
||||||
"Message downloading sleep time(ms)": "Message downloading sleep time(ms)",
|
"Message downloading sleep time(ms)": "Message downloading sleep time(ms)",
|
||||||
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
||||||
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
||||||
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room"
|
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room",
|
||||||
|
"Navigation": "Navigation",
|
||||||
|
"Calls": "Calls",
|
||||||
|
"Room List": "Room List",
|
||||||
|
"Autocomplete": "Autocomplete",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Alt Gr": "Alt Gr",
|
||||||
|
"Shift": "Shift",
|
||||||
|
"Super": "Super",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Bold": "Toggle Bold",
|
||||||
|
"Toggle Italics": "Toggle Italics",
|
||||||
|
"Toggle Quote": "Toggle Quote",
|
||||||
|
"Toggle Markdown": "Toggle Markdown",
|
||||||
|
"New line": "New line",
|
||||||
|
"Navigate recent messages to edit": "Navigate recent messages to edit",
|
||||||
|
"Jump to start/end of the composer": "Jump to start/end of the composer",
|
||||||
|
"Toggle microphone mute": "Toggle microphone mute",
|
||||||
|
"Toggle video on/off": "Toggle video on/off",
|
||||||
|
"Jump to room search": "Jump to room search",
|
||||||
|
"Navigate up/down in the room list": "Navigate up/down in the room list",
|
||||||
|
"Select room from the room list": "Select room from the room list",
|
||||||
|
"Collapse room list section": "Collapse room list section",
|
||||||
|
"Expand room list section": "Expand room list section",
|
||||||
|
"Clear room list filter field": "Clear room list filter field",
|
||||||
|
"Scroll up/down in the timeline": "Scroll up/down in the timeline",
|
||||||
|
"Toggle the top left menu": "Toggle the top left menu",
|
||||||
|
"Close dialog or context menu": "Close dialog or context menu",
|
||||||
|
"Activate selected button": "Activate selected button",
|
||||||
|
"Toggle this dialog": "Toggle this dialog",
|
||||||
|
"Move autocomplete selection up/down": "Move autocomplete selection up/down",
|
||||||
|
"Cancel autocomplete": "Cancel autocomplete",
|
||||||
|
"Page Up": "Page Up",
|
||||||
|
"Page Down": "Page Down",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Enter": "Enter",
|
||||||
|
"Space": "Space",
|
||||||
|
"End": "End"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1178,6 +1178,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.3.0"
|
"@babel/types" "^7.3.0"
|
||||||
|
|
||||||
|
"@types/classnames@^2.2.10":
|
||||||
|
version "2.2.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999"
|
||||||
|
integrity sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ==
|
||||||
|
|
||||||
"@types/events@*":
|
"@types/events@*":
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||||
|
|
Loading…
Reference in a new issue