Make the Keyboard Shortcuts
dialog into a settings tab (#7198)
This commit is contained in:
parent
cb42173e11
commit
1f298250b9
13 changed files with 191 additions and 155 deletions
|
@ -32,7 +32,6 @@ import SettingsStore from "../../settings/SettingsStore";
|
|||
import ResizeHandle from '../views/elements/ResizeHandle';
|
||||
import { CollapseDistributor, Resizer } from '../../resizer';
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import * as KeyboardShortcuts from "../../accessibility/KeyboardShortcuts";
|
||||
import HomePage from "./HomePage";
|
||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||
import PlatformPeg from "../../PlatformPeg";
|
||||
|
@ -67,6 +66,8 @@ import GroupFilterPanel from './GroupFilterPanel';
|
|||
import CustomRoomTagPanel from './CustomRoomTagPanel';
|
||||
import { mediaFromMxc } from "../../customisations/Media";
|
||||
import LegacyCommunityPreview from "./LegacyCommunityPreview";
|
||||
import { UserTab } from "../views/dialogs/UserSettingsDialog";
|
||||
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
||||
import RightPanelStore from '../../stores/right-panel/RightPanelStore';
|
||||
|
||||
// We need to fetch each pinned message individually (if we don't already have it)
|
||||
|
@ -472,8 +473,11 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
dis.fire(Action.ToggleUserMenu);
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.ToggleShortCutDialog:
|
||||
KeyboardShortcuts.toggleDialog();
|
||||
case NavigationAction.OpenShortCutDialog:
|
||||
dis.dispatch<OpenToTabPayload>({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: UserTab.Keyboard,
|
||||
});
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.GoToHome:
|
||||
|
|
|
@ -36,6 +36,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
|
|||
import BaseDialog from "./BaseDialog";
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import SidebarUserSettingsTab from "../settings/tabs/user/SidebarUserSettingsTab";
|
||||
import KeyboardUserSettingsTab from "../settings/tabs/user/KeyboardUserSettingsTab";
|
||||
|
||||
export enum UserTab {
|
||||
General = "USER_GENERAL_TAB",
|
||||
|
@ -43,6 +44,7 @@ export enum UserTab {
|
|||
Flair = "USER_FLAIR_TAB",
|
||||
Notifications = "USER_NOTIFICATIONS_TAB",
|
||||
Preferences = "USER_PREFERENCES_TAB",
|
||||
Keyboard = "USER_KEYBOARD_TAB",
|
||||
Sidebar = "USER_SIDEBAR_TAB",
|
||||
Voice = "USER_VOICE_TAB",
|
||||
Security = "USER_SECURITY_TAB",
|
||||
|
@ -119,6 +121,12 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
|
|||
"mx_UserSettingsDialog_preferencesIcon",
|
||||
<PreferencesUserSettingsTab closeSettingsFn={this.props.onFinished} />,
|
||||
));
|
||||
tabs.push(new Tab(
|
||||
UserTab.Keyboard,
|
||||
_td("Keyboard"),
|
||||
"mx_UserSettingsDialog_keyboardIcon",
|
||||
<KeyboardUserSettingsTab />,
|
||||
));
|
||||
|
||||
if (SettingsStore.getValue("feature_spaces_metaspaces")) {
|
||||
tabs.push(new Tab(
|
||||
|
|
|
@ -25,7 +25,6 @@ import SdkConfig from "../../../../../SdkConfig";
|
|||
import createRoom from "../../../../../createRoom";
|
||||
import Modal from "../../../../../Modal";
|
||||
import PlatformPeg from "../../../../../PlatformPeg";
|
||||
import * as KeyboardShortcuts from "../../../../../accessibility/KeyboardShortcuts";
|
||||
import UpdateCheckButton from "../../UpdateCheckButton";
|
||||
import { replaceableComponent } from "../../../../../utils/replaceableComponent";
|
||||
import { copyPlaintext } from "../../../../../utils/strings";
|
||||
|
@ -33,6 +32,10 @@ import * as ContextMenu from "../../../../structures/ContextMenu";
|
|||
import { toRightOf } from "../../../../structures/ContextMenu";
|
||||
import BugReportDialog from '../../../dialogs/BugReportDialog';
|
||||
import GenericTextContextMenu from "../../../context_menus/GenericTextContextMenu";
|
||||
import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload";
|
||||
import { Action } from "../../../../../dispatcher/actions";
|
||||
import { UserTab } from "../../../dialogs/UserSettingsDialog";
|
||||
import dis from "../../../../../dispatcher/dispatcher";
|
||||
|
||||
interface IProps {
|
||||
closeSettingsFn: () => void;
|
||||
|
@ -211,6 +214,13 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
|
|||
this.copy(`${appVersion}\n${olmVersion}`, e);
|
||||
};
|
||||
|
||||
private onKeyboardShortcutsClicked = (): void => {
|
||||
dis.dispatch<OpenToTabPayload>({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: UserTab.Keyboard,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const brand = SdkConfig.get().brand;
|
||||
|
||||
|
@ -307,7 +317,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
|
|||
<div className='mx_SettingsTab_subsectionText'>
|
||||
{ faqText }
|
||||
</div>
|
||||
<AccessibleButton kind="primary" onClick={KeyboardShortcuts.toggleDialog}>
|
||||
<AccessibleButton kind="primary" onClick={this.onKeyboardShortcutsClicked}>
|
||||
{ _t("Keyboard Shortcuts") }
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
||||
|
||||
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 classNames from "classnames";
|
||||
import React from "react";
|
||||
|
||||
import { Categories, DIGITS, IShortcut, Modifiers, shortcuts } from "../../../../../accessibility/KeyboardShortcuts";
|
||||
import { isMac, Key } from "../../../../../Keyboard";
|
||||
import { _t, _td } from "../../../../../languageHandler";
|
||||
|
||||
// TS: once languageHandler is TS we can probably inline this into the enum
|
||||
_td("Alt");
|
||||
_td("Alt Gr");
|
||||
_td("Shift");
|
||||
_td("Super");
|
||||
_td("Ctrl");
|
||||
_td("Navigation");
|
||||
_td("Calls");
|
||||
_td("Composer");
|
||||
_td("Room List");
|
||||
_td("Autocomplete");
|
||||
|
||||
const categoryOrder = [
|
||||
Categories.COMPOSER,
|
||||
Categories.AUTOCOMPLETE,
|
||||
Categories.ROOM,
|
||||
Categories.ROOM_LIST,
|
||||
Categories.NAVIGATION,
|
||||
Categories.CALLS,
|
||||
];
|
||||
|
||||
const modifierIcon: Record<string, string> = {
|
||||
[Modifiers.COMMAND]: "⌘",
|
||||
};
|
||||
|
||||
if (isMac) {
|
||||
modifierIcon[Modifiers.ALT] = "⌥";
|
||||
}
|
||||
|
||||
const alternateKeyName: Record<string, string> = {
|
||||
[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"),
|
||||
[DIGITS]: _td("[number]"),
|
||||
};
|
||||
const keyIcon: Record<string, string> = {
|
||||
[Key.ARROW_UP]: "↑",
|
||||
[Key.ARROW_DOWN]: "↓",
|
||||
[Key.ARROW_LEFT]: "←",
|
||||
[Key.ARROW_RIGHT]: "→",
|
||||
};
|
||||
|
||||
interface IShortcutProps {
|
||||
shortcut: IShortcut;
|
||||
}
|
||||
|
||||
const Shortcut: React.FC<IShortcutProps> = ({ 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>;
|
||||
};
|
||||
|
||||
const KeyboardUserSettingsTab: React.FC = () => {
|
||||
return <div className="mx_SettingsTab mx_KeyboardUserSettingsTab">
|
||||
<div className="mx_SettingsTab_heading">{ _t("Keyboard") }</div>
|
||||
<div className="mx_SettingsTab_section">
|
||||
{ categoryOrder.map(category => {
|
||||
const list = shortcuts[category];
|
||||
return <div className="mx_KeyboardShortcutsDialog_category" key={category}>
|
||||
<h3>{ _t(category) }</h3>
|
||||
<div>{ list.map(shortcut => <Shortcut key={shortcut.description} shortcut={shortcut} />) }</div>
|
||||
</div>;
|
||||
}) }
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
export default KeyboardUserSettingsTab;
|
|
@ -26,7 +26,6 @@ import PlatformPeg from "../../../../../PlatformPeg";
|
|||
import { SettingLevel } from "../../../../../settings/SettingLevel";
|
||||
import { replaceableComponent } from "../../../../../utils/replaceableComponent";
|
||||
import SettingsFlag from '../../../elements/SettingsFlag';
|
||||
import * as KeyboardShortcuts from "../../../../../accessibility/KeyboardShortcuts";
|
||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||
import GroupAvatar from "../../../avatars/GroupAvatar";
|
||||
import dis from "../../../../../dispatcher/dispatcher";
|
||||
|
@ -36,6 +35,8 @@ import { useDispatcher } from "../../../../../hooks/useDispatcher";
|
|||
import { CreateEventField, IGroupSummary } from "../../../dialogs/CreateSpaceFromCommunityDialog";
|
||||
import { createSpaceFromCommunity } from "../../../../../utils/space";
|
||||
import Spinner from "../../../elements/Spinner";
|
||||
import { UserTab } from "../../../dialogs/UserSettingsDialog";
|
||||
import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload";
|
||||
import { Action } from "../../../../../dispatcher/actions";
|
||||
|
||||
interface IProps {
|
||||
|
@ -296,6 +297,13 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
|
|||
});
|
||||
}
|
||||
|
||||
private onKeyboardShortcutsClicked = (): void => {
|
||||
dis.dispatch<OpenToTabPayload>({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: UserTab.Keyboard,
|
||||
});
|
||||
};
|
||||
|
||||
getShowLocationIfEnabled(): string[] {
|
||||
// TODO: when location sharing is out of labs, this can be deleted and
|
||||
// we can just add this to COMPOSER_SETTINGS
|
||||
|
@ -372,7 +380,7 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
|
|||
<span className="mx_SettingsTab_subheading">{ _t("Keyboard shortcuts") }</span>
|
||||
<div className="mx_SettingsFlag">
|
||||
{ _t("To view all keyboard shortcuts, <a>click here</a>.", {}, {
|
||||
a: sub => <AccessibleButton kind="link" onClick={KeyboardShortcuts.toggleDialog}>
|
||||
a: sub => <AccessibleButton kind="link" onClick={this.onKeyboardShortcutsClicked}>
|
||||
{ sub }
|
||||
</AccessibleButton>,
|
||||
}) }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue