feature: keyboard shortcuts and tips (#258)
* feature: draft of the feature * fix: default state of the modal * feature: shortcuts and tips * feature: typo * refactor: deletes "Can be used to" * refactor: default state to close * style: consisten keyboard layout * fix: - third scroll bar * fix: styling correction alligh all text to baseline * refactor: rewrite on maner of MS Teams * fix: initial state - false Co-authored-by: kunzheng <58841788+kunzms@users.noreply.github.com>
This commit is contained in:
Родитель
2a3383d4a0
Коммит
37aa859a80
|
@ -12,6 +12,7 @@ import IAppErrorActions, * as appErrorActions from "./redux/actions/appErrorActi
|
|||
import { ErrorHandler } from "./react/components/common/errorHandler/errorHandler";
|
||||
import { KeyboardManager } from "./react/components/common/keyboardManager/keyboardManager";
|
||||
import { HelpMenu } from "./react/components/shell/helpMenu";
|
||||
import { KeyboardShortcuts } from "./react/components/shell/keyboardShortcuts";
|
||||
import { MainContentRouter } from "./react/components/shell/mainContentRouter";
|
||||
import { Sidebar } from "./react/components/shell/sidebar";
|
||||
import { StatusBar } from "./react/components/shell/statusBar";
|
||||
|
@ -77,7 +78,12 @@ export default class App extends React.Component<IAppProps> {
|
|||
<BrowserRouter>
|
||||
<div className={`app-shell platform-${platform}`}>
|
||||
<TitleBar icon="TagGroup">
|
||||
<div className="app-help-menu-icon"><HelpMenu/></div>
|
||||
<div className="app-hotkeys-menu-icon">
|
||||
<KeyboardShortcuts />
|
||||
</div>
|
||||
<div className="app-help-menu-icon">
|
||||
<HelpMenu />
|
||||
</div>
|
||||
</TitleBar>
|
||||
<div className="app-main">
|
||||
<Sidebar project={this.props.currentProject} />
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -322,6 +322,68 @@ export const english: IAppStrings = {
|
|||
profile: {
|
||||
settings: "Profile Settings",
|
||||
},
|
||||
shortcuts: {
|
||||
squareBrackets: {
|
||||
keys: {
|
||||
leftBracket: "[",
|
||||
rightBracket: "]",
|
||||
},
|
||||
description: {
|
||||
prevWord: "Move the selection to previous word",
|
||||
nextWord: "Move the selection to next word",
|
||||
},
|
||||
},
|
||||
greaterAndLessThan: {
|
||||
keys: {
|
||||
lessThan: "<",
|
||||
greaterThan: ">",
|
||||
},
|
||||
description: {
|
||||
prevPage: "Go to the previous page in multi-pages documents",
|
||||
nextPage: "Go to the next page in multi-pages documents",
|
||||
},
|
||||
},
|
||||
zoomKeys: {
|
||||
keys: {
|
||||
minus: "-",
|
||||
plus: "=",
|
||||
slash: "/",
|
||||
},
|
||||
description: {
|
||||
in: "Zoom in",
|
||||
out: "Zoom out",
|
||||
reset: "Reset zoom",
|
||||
},
|
||||
},
|
||||
deleteAndBackspace: {
|
||||
keys: {
|
||||
delete: "Delete",
|
||||
backSpace: "Backspace",
|
||||
},
|
||||
description: {
|
||||
delete: "Delete selection from document map or selection key from a label",
|
||||
backSpace: "Delete selection from document map or selection key from a label",
|
||||
},
|
||||
},
|
||||
tips: {
|
||||
quickLabeling: {
|
||||
name: "Quick labeling",
|
||||
description: "Hotkeys of 1 through 0 and all letters are assigned to first 36 tags, after you selected one or multiple words from the highlighted text elements, by pressing these hotkeys, you can label the selected words.",
|
||||
},
|
||||
renameTag: {
|
||||
name: "Rename Tag",
|
||||
description: "Hold Alt key and click on tag name, user can change the tag's name.",
|
||||
},
|
||||
multipleWordSelection: {
|
||||
name: "Multiple words selection",
|
||||
description: "Click and hold on word, than hover over other words to do multiple words selection at a time.",
|
||||
},
|
||||
},
|
||||
headers: {
|
||||
keyboardShortcuts: "Keyboard shortcuts",
|
||||
otherTips: "Other tips",
|
||||
},
|
||||
},
|
||||
errors: {
|
||||
unknown: {
|
||||
title: "Unknown Error",
|
||||
|
|
|
@ -325,6 +325,68 @@ export const spanish: IAppStrings = {
|
|||
profile: {
|
||||
settings: "Configuración de Perfíl",
|
||||
},
|
||||
shortcuts: {
|
||||
squareBrackets: {
|
||||
keys: {
|
||||
leftBracket: "[",
|
||||
rightBracket: "]",
|
||||
},
|
||||
description: {
|
||||
prevWord: "Mover la selección a la palabra anterior",
|
||||
nextWord: "Mover la selección a la siguiente palabra",
|
||||
},
|
||||
},
|
||||
greaterAndLessThan: {
|
||||
keys: {
|
||||
lessThan: "<",
|
||||
greaterThan: ">",
|
||||
},
|
||||
description: {
|
||||
prevPage: "Ir a la página anterior en documentos de varias páginas",
|
||||
nextPage: "Ir a la página siguiente en documentos de varias páginas",
|
||||
},
|
||||
},
|
||||
zoomKeys: {
|
||||
keys: {
|
||||
minus: "-",
|
||||
plus: "=",
|
||||
slash: "/",
|
||||
},
|
||||
description: {
|
||||
in: "Acercarse",
|
||||
out: "Disminuir el zoom",
|
||||
reset: "Restablecer zoom",
|
||||
},
|
||||
},
|
||||
deleteAndBackspace: {
|
||||
keys: {
|
||||
delete: "Delete",
|
||||
backSpace: "Backspace",
|
||||
},
|
||||
description: {
|
||||
delete: "Eliminar selección del mapa del documento o clave de selección de una etiqueta",
|
||||
backSpace: "Eliminar selección del mapa del documento o clave de selección de una etiqueta",
|
||||
},
|
||||
},
|
||||
tips: {
|
||||
quickLabeling: {
|
||||
name: "Etiquetado rápido",
|
||||
description: "Las teclas de acceso rápido de 1 a 0 y todas las letras se asignan a las primeras 36 etiquetas, después de seleccionar una o varias palabras de los elementos de texto resaltados, al presionar estas teclas de acceso rápido, puede etiquetar las palabras seleccionadas.",
|
||||
},
|
||||
renameTag: {
|
||||
name: "Rename Tag",
|
||||
description: "Mantenga presionada la tecla Alt y haga clic en el nombre de la etiqueta, el usuario puede cambiar el nombre de la etiqueta.",
|
||||
},
|
||||
multipleWordSelection: {
|
||||
name: "Selección de palabras múltiples",
|
||||
description: "Haga clic y mantenga presionada la palabra, luego desplace el cursor sobre otras palabras para seleccionar varias palabras a la vez.",
|
||||
},
|
||||
},
|
||||
headers: {
|
||||
keyboardShortcuts: "Atajos de teclado",
|
||||
otherTips: "Otros consejos",
|
||||
},
|
||||
},
|
||||
errors: {
|
||||
unknown: {
|
||||
title: "Error desconocido",
|
||||
|
|
|
@ -317,6 +317,68 @@ export interface IAppStrings {
|
|||
profile: {
|
||||
settings: string;
|
||||
};
|
||||
shortcuts: {
|
||||
squareBrackets: {
|
||||
keys: {
|
||||
leftBracket: string,
|
||||
rightBracket: string,
|
||||
},
|
||||
description: {
|
||||
prevWord: string,
|
||||
nextWord: string,
|
||||
},
|
||||
},
|
||||
greaterAndLessThan: {
|
||||
keys: {
|
||||
lessThan: string,
|
||||
greaterThan: string,
|
||||
},
|
||||
description: {
|
||||
prevPage: string,
|
||||
nextPage: string,
|
||||
},
|
||||
},
|
||||
zoomKeys: {
|
||||
keys: {
|
||||
minus: string,
|
||||
plus: string,
|
||||
slash: string,
|
||||
},
|
||||
description: {
|
||||
in: string,
|
||||
out: string,
|
||||
reset: string,
|
||||
},
|
||||
},
|
||||
deleteAndBackspace: {
|
||||
keys: {
|
||||
delete: string,
|
||||
backSpace: string,
|
||||
},
|
||||
description: {
|
||||
delete: string,
|
||||
backSpace: string,
|
||||
},
|
||||
},
|
||||
tips: {
|
||||
quickLabeling: {
|
||||
name: string,
|
||||
description: string,
|
||||
},
|
||||
renameTag: {
|
||||
name: string,
|
||||
description: string,
|
||||
},
|
||||
multipleWordSelection: {
|
||||
name: string,
|
||||
description: string,
|
||||
},
|
||||
},
|
||||
headers: {
|
||||
keyboardShortcuts: string,
|
||||
otherTips: string,
|
||||
},
|
||||
};
|
||||
errors: {
|
||||
unknown: IErrorMetadata,
|
||||
projectInvalidJson: IErrorMetadata,
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
"name": "Add",
|
||||
"unicode": "E710"
|
||||
},
|
||||
{
|
||||
"name": "Cancel",
|
||||
"unicode": "E711"
|
||||
},
|
||||
{
|
||||
"name": "Settings",
|
||||
"unicode": "E713"
|
||||
|
@ -58,10 +62,6 @@
|
|||
"name": "CheckboxComposite",
|
||||
"unicode": "E73A"
|
||||
},
|
||||
{
|
||||
"name": "LabelComposite",
|
||||
"unicode": "E932"
|
||||
},
|
||||
{
|
||||
"name": "CheckMark",
|
||||
"unicode": "E73E"
|
||||
|
@ -126,6 +126,10 @@
|
|||
"name": "Tag",
|
||||
"unicode": "E8EC"
|
||||
},
|
||||
{
|
||||
"name": "Label",
|
||||
"unicode": "E932"
|
||||
},
|
||||
{
|
||||
"name": "Info",
|
||||
"unicode": "E946"
|
||||
|
@ -177,6 +181,10 @@
|
|||
{
|
||||
"name": "WarningSolid",
|
||||
"unicode": "F736"
|
||||
},
|
||||
{
|
||||
"name": "BookAnswers",
|
||||
"unicode": "F8A4"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
@import "../../../assets/sass/theme.scss";
|
||||
@import "../common/common.scss";
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
margin: 2rem;
|
||||
padding: 4rem 1rem 2rem 2rem;
|
||||
h3, h4, h6 {
|
||||
font-weight: 600;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 4rem;
|
||||
width: calc(100% - 1.5rem);
|
||||
background-color: rgb(30, 32, 36);
|
||||
|
||||
h3 {
|
||||
display: flex;
|
||||
width: 90%;
|
||||
align-self: center;
|
||||
margin-top: 1.5rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
.close-modal {
|
||||
margin: 1.25rem 0rem auto auto;
|
||||
color: #fff;
|
||||
&:hover {
|
||||
color: $lighter-5;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
.description {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
ul {
|
||||
padding: 0;
|
||||
}
|
||||
h6 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.shortcuts-list {
|
||||
overflow-y: auto;
|
||||
.shortcut {
|
||||
display: flex;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||||
margin: 0.5rem;
|
||||
margin-left: 0;
|
||||
&-description {
|
||||
align-self: center;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-right: 0.125rem;
|
||||
width: 70%;
|
||||
}
|
||||
&-keys {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 30%;
|
||||
.keyboard-key {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
background: rgba(49, 52, 58, 0.79);
|
||||
font-weight: 600;
|
||||
height: 2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding: 0 1rem;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// modal icon-button
|
||||
.shortcuts-modal-button {
|
||||
padding: 6px 8px;
|
||||
color: #ccc;
|
||||
display: inline-block;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: $lighter-2;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Modal } from "office-ui-fabric-react/lib/Modal";
|
||||
import { FontIcon, IFontIconProps } from "office-ui-fabric-react";
|
||||
import { ICustomizations, Customizer } from "office-ui-fabric-react/lib/Utilities";
|
||||
import { useId } from "@uifabric/react-hooks";
|
||||
import { getDarkGreyTheme } from "../../../common/themes";
|
||||
import { strings } from "../../../common/strings";
|
||||
|
||||
import "./keyboardShortcuts.scss";
|
||||
|
||||
export interface IHotKeysModalState {
|
||||
showModal: boolean;
|
||||
}
|
||||
interface IKey {
|
||||
key: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const KeyboardShortcuts: React.FC = () => {
|
||||
const dark: ICustomizations = {
|
||||
settings: {
|
||||
theme: getDarkGreyTheme(),
|
||||
},
|
||||
scopedSettings: {},
|
||||
};
|
||||
const uniqueId: string = useId("shortcuts");
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const closeModal = () => setShowModal(false);
|
||||
|
||||
const shortcutsItems: IKey[] = [
|
||||
{
|
||||
key: strings.shortcuts.squareBrackets.keys.leftBracket,
|
||||
description: strings.shortcuts.squareBrackets.description.prevWord,
|
||||
},
|
||||
{
|
||||
key: strings.shortcuts.squareBrackets.keys.rightBracket,
|
||||
description: strings.shortcuts.squareBrackets.description.nextWord,
|
||||
},
|
||||
{
|
||||
key: strings.shortcuts.greaterAndLessThan.keys.lessThan,
|
||||
description: strings.shortcuts.greaterAndLessThan.description.prevPage,
|
||||
},
|
||||
{
|
||||
key: strings.shortcuts.greaterAndLessThan.keys.greaterThan,
|
||||
description: strings.shortcuts.greaterAndLessThan.description.nextPage,
|
||||
},
|
||||
{
|
||||
key: strings.shortcuts.zoomKeys.keys.minus,
|
||||
description: strings.shortcuts.zoomKeys.description.out,
|
||||
},
|
||||
{
|
||||
key: strings.shortcuts.zoomKeys.keys.plus,
|
||||
description: strings.shortcuts.zoomKeys.description.in,
|
||||
},
|
||||
{
|
||||
key: strings.shortcuts.zoomKeys.keys.slash,
|
||||
description: strings.shortcuts.zoomKeys.description.reset,
|
||||
},
|
||||
{
|
||||
key: strings.shortcuts.deleteAndBackspace.keys.delete,
|
||||
description: strings.shortcuts.deleteAndBackspace.description.delete,
|
||||
},
|
||||
{
|
||||
key: strings.shortcuts.deleteAndBackspace.keys.backSpace,
|
||||
description: strings.shortcuts.deleteAndBackspace.description.backSpace,
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
const tipsItems = [
|
||||
{
|
||||
name: strings.shortcuts.tips.quickLabeling.name,
|
||||
description: strings.shortcuts.tips.quickLabeling.description,
|
||||
},
|
||||
{
|
||||
name: strings.shortcuts.tips.renameTag.name,
|
||||
description: strings.shortcuts.tips.renameTag.description,
|
||||
},
|
||||
{
|
||||
name: strings.shortcuts.tips.multipleWordSelection.name,
|
||||
description: strings.shortcuts.tips.multipleWordSelection.description,
|
||||
},
|
||||
];
|
||||
const ShortcutsListItem = ({ item }): JSX.Element => {
|
||||
return (
|
||||
<li key={uniqueId} className="shortcut">
|
||||
<div className="shortcut-description description">{item.description}</div>
|
||||
<div className="shortcut-keys">
|
||||
<span
|
||||
key={uniqueId}
|
||||
className="keyboard-key"
|
||||
aria-label={`keyboard key - ${item.key}`}
|
||||
>{item.key}</span>
|
||||
</div>
|
||||
</li>);
|
||||
};
|
||||
|
||||
const TipsListItem = ({ item }): JSX.Element => (
|
||||
<li key={uniqueId}>
|
||||
<h6>{item.name}</h6>
|
||||
<p className="description">{item.description}</p>
|
||||
</li>
|
||||
);
|
||||
|
||||
return (
|
||||
<Customizer {...dark}>
|
||||
<FontIcon
|
||||
className="shortcuts-modal-button"
|
||||
iconName="BookAnswers"
|
||||
role="button"
|
||||
onClick={() => setShowModal(true)}
|
||||
/>
|
||||
<Modal
|
||||
titleAriaId={"Hot Keys Modal"}
|
||||
isOpen={showModal}
|
||||
onDismiss={closeModal}
|
||||
isBlocking={false}
|
||||
containerClassName="container"
|
||||
// className="container"
|
||||
>
|
||||
<div className="header">
|
||||
<h3>{strings.shortcuts.headers.keyboardShortcuts}</h3>
|
||||
<FontIcon className="close-modal" role="button" onClick={closeModal} iconName="Cancel" />
|
||||
</div>
|
||||
<div className="content">
|
||||
<div className="shortcuts-list-container">
|
||||
<ul className="shortcuts-list">
|
||||
{
|
||||
shortcutsItems.map((item) => <ShortcutsListItem item={item} />)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="tips-list-container">
|
||||
<h4 >{strings.shortcuts.headers.otherTips}</h4>
|
||||
<ul className="tips-list">
|
||||
{
|
||||
tipsItems.map((item) => <TipsListItem item={item} />)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</Customizer>
|
||||
);
|
||||
};
|
|
@ -52,6 +52,9 @@ export function registerIcons() {
|
|||
Filter: "\uE71C",
|
||||
Table: "\uED86",
|
||||
MapLayers: "\uE81E",
|
||||
BookAnswers: "\uF8A4",
|
||||
Cancel: "\uE711",
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче