feat: Creates a modal showing all the available keyboard shortcuts (#2728)
* feat: Adds modal showing all the available keyboard shortcuts * Minor fixes * Minor fixes * Spacing fixes * fix translations * Adds i18n * Review fixes * Review fixes * spacing fixes * Review fixes * Minor fixes Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
parent
bdc4ecffc1
commit
c3314dd186
8 changed files with 353 additions and 1 deletions
|
@ -175,6 +175,9 @@ export default {
|
||||||
const allConversations = document.querySelectorAll(
|
const allConversations = document.querySelectorAll(
|
||||||
'.conversations-list .conversation'
|
'.conversations-list .conversation'
|
||||||
);
|
);
|
||||||
|
if (hasPressedAltAndMKey(e)) {
|
||||||
|
this.$refs.arrowDownButton.$el.click();
|
||||||
|
}
|
||||||
if (hasPressedAltAndEKey(e)) {
|
if (hasPressedAltAndEKey(e)) {
|
||||||
const activeConversation = document.querySelector(
|
const activeConversation = document.querySelector(
|
||||||
'div.conversations-list div.conversation.active'
|
'div.conversations-list div.conversation.active'
|
||||||
|
|
|
@ -50,10 +50,17 @@
|
||||||
:show="showOptionsMenu"
|
:show="showOptionsMenu"
|
||||||
@toggle-accounts="toggleAccountModal"
|
@toggle-accounts="toggleAccountModal"
|
||||||
@show-support-chat-window="toggleSupportChatWindow"
|
@show-support-chat-window="toggleSupportChatWindow"
|
||||||
|
@key-shortcut-modal="toggleKeyShortcutModal"
|
||||||
@close="toggleOptions"
|
@close="toggleOptions"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<woot-key-shortcut-modal
|
||||||
|
v-if="showShortcutModal"
|
||||||
|
@close="closeKeyShortcutModal"
|
||||||
|
@clickaway="closeKeyShortcutModal"
|
||||||
|
/>
|
||||||
|
|
||||||
<account-selector
|
<account-selector
|
||||||
:show-account-modal="showAccountModal"
|
:show-account-modal="showAccountModal"
|
||||||
@close-account-modal="toggleAccountModal"
|
@close-account-modal="toggleAccountModal"
|
||||||
|
@ -86,6 +93,9 @@ import OptionsMenu from './sidebarComponents/OptionsMenu.vue';
|
||||||
import AccountSelector from './sidebarComponents/AccountSelector.vue';
|
import AccountSelector from './sidebarComponents/AccountSelector.vue';
|
||||||
import AddAccountModal from './sidebarComponents/AddAccountModal.vue';
|
import AddAccountModal from './sidebarComponents/AddAccountModal.vue';
|
||||||
import AddLabelModal from '../../routes/dashboard/settings/labels/AddLabel';
|
import AddLabelModal from '../../routes/dashboard/settings/labels/AddLabel';
|
||||||
|
import WootKeyShortcutModal from 'components/widgets/modal/WootKeyShortcutModal';
|
||||||
|
import { hasPressedCommandAndForwardSlash } from 'shared/helpers/KeyboardHelpers';
|
||||||
|
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -97,14 +107,16 @@ export default {
|
||||||
AccountSelector,
|
AccountSelector,
|
||||||
AddAccountModal,
|
AddAccountModal,
|
||||||
AddLabelModal,
|
AddLabelModal,
|
||||||
|
WootKeyShortcutModal,
|
||||||
},
|
},
|
||||||
mixins: [adminMixin, alertMixin],
|
mixins: [adminMixin, alertMixin, eventListenerMixins],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showOptionsMenu: false,
|
showOptionsMenu: false,
|
||||||
showAccountModal: false,
|
showAccountModal: false,
|
||||||
showCreateAccountModal: false,
|
showCreateAccountModal: false,
|
||||||
showAddLabelModal: false,
|
showAddLabelModal: false,
|
||||||
|
showShortcutModal: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -254,7 +266,19 @@ export default {
|
||||||
this.$store.dispatch('teams/get');
|
this.$store.dispatch('teams/get');
|
||||||
this.setChatwootUser();
|
this.setChatwootUser();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
toggleKeyShortcutModal() {
|
||||||
|
this.showShortcutModal = true;
|
||||||
|
},
|
||||||
|
closeKeyShortcutModal() {
|
||||||
|
this.showShortcutModal = false;
|
||||||
|
},
|
||||||
|
handleKeyEvents(e) {
|
||||||
|
if (hasPressedCommandAndForwardSlash(e)) {
|
||||||
|
this.toggleKeyShortcutModal();
|
||||||
|
}
|
||||||
|
},
|
||||||
toggleSupportChatWindow() {
|
toggleSupportChatWindow() {
|
||||||
window.$chatwoot.toggle();
|
window.$chatwoot.toggle();
|
||||||
},
|
},
|
||||||
|
|
|
@ -26,6 +26,16 @@
|
||||||
Contact Support
|
Contact Support
|
||||||
</woot-button>
|
</woot-button>
|
||||||
</woot-dropdown-item>
|
</woot-dropdown-item>
|
||||||
|
<woot-dropdown-item>
|
||||||
|
<woot-button
|
||||||
|
variant="clear"
|
||||||
|
size="small"
|
||||||
|
class=" change-accounts--button"
|
||||||
|
@click="$emit('key-shortcut-modal')"
|
||||||
|
>
|
||||||
|
{{ $t('SIDEBAR_ITEMS.KEYBOARD_SHORTCUTS') }}
|
||||||
|
</woot-button>
|
||||||
|
</woot-dropdown-item>
|
||||||
<woot-dropdown-item>
|
<woot-dropdown-item>
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/app/accounts/${accountId}/profile/settings`"
|
:to="`/app/accounts/${accountId}/profile/settings`"
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import WootKeyboardShortcutModal from './WootKeyShortcutModal.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/Shortcuts/Keyboard Shortcut',
|
||||||
|
component: WootKeyboardShortcutModal,
|
||||||
|
argTypes: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Template = (args, { argTypes }) => ({
|
||||||
|
props: Object.keys(argTypes),
|
||||||
|
components: { WootKeyboardShortcutModal },
|
||||||
|
template:
|
||||||
|
'<woot-keyboard-shortcut-modal v-bind="$props"></woot-keyboard-shortcut-modal>',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const KeyboardShortcut = Template.bind({});
|
||||||
|
KeyboardShortcut.args = {};
|
|
@ -0,0 +1,182 @@
|
||||||
|
<template>
|
||||||
|
<transition name="slide-up">
|
||||||
|
<div class="modal-mask">
|
||||||
|
<div v-on-clickaway="() => $emit('clickaway')" class="modal-container">
|
||||||
|
<div class="header-wrap">
|
||||||
|
<div class="title-shortcut-key__wrap">
|
||||||
|
<h2 class="page-title">
|
||||||
|
{{ $t('SIDEBAR_ITEMS.KEYBOARD_SHORTCUTS') }}
|
||||||
|
</h2>
|
||||||
|
<div class="shortcut-key__wrap">
|
||||||
|
<p class="shortcut-key">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.COMMAND_KEY') }}
|
||||||
|
</p>
|
||||||
|
<p class="shortcut-key key">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.FORWARD_SLASH_KEY') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<i class="ion-android-close modal--close" @click="$emit('close')"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="shortcut__wrap">
|
||||||
|
<div class="title-key__wrap">
|
||||||
|
<span class="sub-block-title">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.TITLE.OPEN_CONVERSATION') }}
|
||||||
|
</span>
|
||||||
|
<div class="shortcut-key__wrap">
|
||||||
|
<div class="open-conversation__key">
|
||||||
|
<span class="shortcut-key">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }}
|
||||||
|
</span>
|
||||||
|
<span class="shortcut-key">
|
||||||
|
J
|
||||||
|
</span>
|
||||||
|
<span class="forward-slash sub-block-title">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.FORWARD_SLASH_KEY') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span class="shortcut-key">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }}
|
||||||
|
</span>
|
||||||
|
<span class="shortcut-key key">
|
||||||
|
K
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="title-key__wrap">
|
||||||
|
<span class="sub-block-title">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.TITLE.RESOLVE_AND_NEXT') }}
|
||||||
|
</span>
|
||||||
|
<div class="shortcut-key__wrap">
|
||||||
|
<span class="shortcut-key">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.COMMAND_KEY') }}
|
||||||
|
</span>
|
||||||
|
<span class="shortcut-key">
|
||||||
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }}
|
||||||
|
</span>
|
||||||
|
<span class="shortcut-key key">
|
||||||
|
E
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="shortcutKey in shortcutKeys"
|
||||||
|
:key="shortcutKey.id"
|
||||||
|
class="title-key__wrap"
|
||||||
|
>
|
||||||
|
<span class="sub-block-title">
|
||||||
|
{{ title(shortcutKey) }}
|
||||||
|
</span>
|
||||||
|
<div class="shortcut-key__wrap">
|
||||||
|
<span class="shortcut-key">
|
||||||
|
{{ shortcutKey.firstkey }}
|
||||||
|
</span>
|
||||||
|
<span class="shortcut-key key">
|
||||||
|
{{ shortcutKey.secondKey }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mixin as clickaway } from 'vue-clickaway';
|
||||||
|
import { SHORTCUT_KEYS } from './constants';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [clickaway],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
shortcutKeys: SHORTCUT_KEYS,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
title(item) {
|
||||||
|
return this.$t(`KEYBOARD_SHORTCUTS.TITLE.${item.label}`);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.modal-container {
|
||||||
|
padding: var(--space-medium) var(--space-large) var(--space-large)
|
||||||
|
var(--space-large);
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-shortcut-key__wrap {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: var(--space-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: var(--font-size-big);
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shortcut-key__wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: var(--space-smaller);
|
||||||
|
margin-left: var(--space-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shortcut__wrap {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 0.5fr);
|
||||||
|
gap: var(--space-smaller) var(--space-large);
|
||||||
|
margin-top: var(--space-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-key__wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-block-title {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.forward-slash {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shortcut-key {
|
||||||
|
background: var(--color-background);
|
||||||
|
padding: var(--space-small) var(--space-one);
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
align-items: center;
|
||||||
|
border-radius: var(--border-radius-normal);
|
||||||
|
margin-right: var(--space-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.key {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: var(--space-large);
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.open-conversation__key {
|
||||||
|
display: flex;
|
||||||
|
margin-right: var(--space-small);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,86 @@
|
||||||
|
export const SHORTCUT_KEYS = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
label: 'NAVIGATE_DROPDOWN',
|
||||||
|
firstkey: 'Up',
|
||||||
|
secondKey: 'Down',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
label: 'RESOLVE_CONVERSATION',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'E',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
label: 'GO_TO_CONVERSATION_DASHBOARD',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'C',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
label: 'ADD_ATTACHMENT',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
label: 'GO_TO_CONTACTS_DASHBOARD',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'V',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
label: 'TOGGLE_SIDEBAR',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'O',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
label: 'GO_TO_REPORTS_SIDEBAR',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'R',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
label: 'MOVE_TO_NEXT_TAB',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'N',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
label: 'GO_TO_SETTINGS',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'S',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
label: 'SWITCH_CONVERSATION_STATUS',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'B',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
label: 'SWITCH_TO_PRIVATE_NOTE',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'P',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 12,
|
||||||
|
label: 'TOGGLE_RICH_CONTENT_EDITOR',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'W',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 13,
|
||||||
|
label: 'SWITCH_TO_REPLY',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'L',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 14,
|
||||||
|
label: 'TOGGLE_SNOOZE_DROPDOWN',
|
||||||
|
firstkey: 'Alt / ⌥',
|
||||||
|
secondKey: 'M',
|
||||||
|
},
|
||||||
|
];
|
|
@ -98,6 +98,7 @@
|
||||||
"CHANGE_ACCOUNTS": "Switch Account",
|
"CHANGE_ACCOUNTS": "Switch Account",
|
||||||
"SELECTOR_SUBTITLE": "Select an account from the following list",
|
"SELECTOR_SUBTITLE": "Select an account from the following list",
|
||||||
"PROFILE_SETTINGS": "Profile Settings",
|
"PROFILE_SETTINGS": "Profile Settings",
|
||||||
|
"KEYBOARD_SHORTCUTS": "Keyboard Shortcuts",
|
||||||
"LOGOUT": "Logout"
|
"LOGOUT": "Logout"
|
||||||
},
|
},
|
||||||
"APP_GLOBAL": {
|
"APP_GLOBAL": {
|
||||||
|
@ -159,5 +160,30 @@
|
||||||
},
|
},
|
||||||
"SUBMIT": "Submit"
|
"SUBMIT": "Submit"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"KEYBOARD_SHORTCUTS": {
|
||||||
|
"TITLE": {
|
||||||
|
"OPEN_CONVERSATION": "Open conversation",
|
||||||
|
"RESOLVE_AND_NEXT": "Resolve and move to next",
|
||||||
|
"NAVIGATE_DROPDOWN": "Navigate dropdown items",
|
||||||
|
"RESOLVE_CONVERSATION": "Resolve Conversation",
|
||||||
|
"GO_TO_CONVERSATION_DASHBOARD": "Go to Conversation Dashboard",
|
||||||
|
"ADD_ATTACHMENT": "Add Attachment",
|
||||||
|
"GO_TO_CONTACTS_DASHBOARD": "Go to Contacts Dashboard",
|
||||||
|
"TOGGLE_SIDEBAR": "Toggle Sidebar",
|
||||||
|
"GO_TO_REPORTS_SIDEBAR": "Go to Reports sidebar",
|
||||||
|
"MOVE_TO_NEXT_TAB": "Move to next tab in conversation list",
|
||||||
|
"GO_TO_SETTINGS": "Go to Settings",
|
||||||
|
"SWITCH_CONVERSATION_STATUS": "Switch Conversation status",
|
||||||
|
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||||
|
"TOGGLE_RICH_CONTENT_EDITOR": "Toggle Rich Content editor",
|
||||||
|
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||||
|
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||||
|
},
|
||||||
|
"KEYS": {
|
||||||
|
"COMMAND_KEY": "⌘",
|
||||||
|
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||||
|
"FORWARD_SLASH_KEY": "/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,10 @@ export const hasPressedShift = e => {
|
||||||
return e.shiftKey;
|
return e.shiftKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const hasPressedCommandAndForwardSlash = e => {
|
||||||
|
return e.metaKey && e.keyCode === 191;
|
||||||
|
};
|
||||||
|
|
||||||
export const hasPressedAltAndCKey = e => {
|
export const hasPressedAltAndCKey = e => {
|
||||||
return e.altKey && e.keyCode === 67;
|
return e.altKey && e.keyCode === 67;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue