Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the Keyboard Shortcuts dialog into a settings tab #7198

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion res/css/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@
@import "./views/dialogs/_IncomingSasDialog.scss";
@import "./views/dialogs/_InviteDialog.scss";
@import "./views/dialogs/_JoinRuleDropdown.scss";
@import "./views/dialogs/_KeyboardShortcutsDialog.scss";
@import "./views/dialogs/_LeaveSpaceDialog.scss";
@import "./views/dialogs/_ManageRestrictedJoinRuleDialog.scss";
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
Expand Down Expand Up @@ -273,6 +272,7 @@
@import "./views/settings/tabs/user/_AppearanceUserSettingsTab.scss";
@import "./views/settings/tabs/user/_GeneralUserSettingsTab.scss";
@import "./views/settings/tabs/user/_HelpUserSettingsTab.scss";
@import "./views/settings/tabs/user/_KeyboardUserSettingsTab.scss";
@import "./views/settings/tabs/user/_LabsUserSettingsTab.scss";
@import "./views/settings/tabs/user/_MjolnirUserSettingsTab.scss";
@import "./views/settings/tabs/user/_NotificationUserSettingsTab.scss";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
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.
Expand All @@ -14,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

.mx_KeyboardShortcutsDialog {
.mx_KeyboardUserSettingsTab .mx_SettingsTab_section {
display: flex;
flex-wrap: wrap;
-webkit-box-orient: vertical;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import * as React from "react";
import classNames from "classnames";

import Modal from "../Modal";
import { _t, _td } from "../languageHandler";
import { _td } from "../languageHandler";
import { isMac, Key } from "../Keyboard";
import InfoDialog from "../components/views/dialogs/InfoDialog";

// 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",
Expand All @@ -38,13 +26,6 @@ export enum Categories {
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 on Mac and displayed as an Icon
ALT_GR = "Alt Gr",
Expand All @@ -65,12 +46,12 @@ interface IKeybind {
key: string; // TS: fix this once Key is an enum
}

interface IShortcut {
export interface IShortcut {
keybinds: IKeybind[];
description: string;
}

const shortcuts: Record<Categories, IShortcut[]> = {
export const shortcuts: Record<Categories, IShortcut[]> = {
[Categories.COMPOSER]: [
{
keybinds: [{
Expand Down Expand Up @@ -291,107 +272,6 @@ const shortcuts: Record<Categories, IShortcut[]> = {
],
};

const categoryOrder = [
Categories.COMPOSER,
Categories.AUTOCOMPLETE,
Categories.ROOM,
Categories.ROOM_LIST,
Categories.NAVIGATION,
Categories.CALLS,
];

interface IModal {
close: () => void;
finished: Promise<any[]>;
}

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]: "→",
};

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 = 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>;
});

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;
},
});
};

export const registerShortcut = (category: Categories, defn: IShortcut) => {
shortcuts[category].push(defn);
};
8 changes: 6 additions & 2 deletions src/components/structures/LoggedInView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import SettingsStore from "../../settings/SettingsStore";
import ResizeHandle from '../views/elements/ResizeHandle';
import { Resizer, CollapseDistributor } 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";
Expand Down Expand Up @@ -70,6 +69,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";

// 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.
Expand Down Expand Up @@ -502,7 +503,10 @@ class LoggedInView extends React.Component<IProps, IState> {
handled = true;
break;
case NavigationAction.ToggleShortCutDialog:
KeyboardShortcuts.toggleDialog();
dis.dispatch<OpenToTabPayload>({
action: Action.ViewUserSettings,
initialTabId: UserTab.Keyboard,
});
SimonBrandner marked this conversation as resolved.
Show resolved Hide resolved
handled = true;
break;
case NavigationAction.GoToHome:
Expand Down
8 changes: 8 additions & 0 deletions src/components/views/dialogs/UserSettingsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ 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",
Appearance = "USER_APPEARANCE_TAB",
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",
Expand Down Expand Up @@ -118,6 +120,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_preferencesIcon",
SimonBrandner marked this conversation as resolved.
Show resolved Hide resolved
<KeyboardUserSettingsTab />,
));

if (SettingsStore.getValue("feature_spaces_metaspaces")) {
tabs.push(new Tab(
Expand Down
14 changes: 12 additions & 2 deletions src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ 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";
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";

import { logger } from "matrix-js-sdk/src/logger";

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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>
Expand Down
Loading