mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 19:17:48 +00:00 
			
		
		
		
	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:
		| @@ -175,6 +175,9 @@ export default { | ||||
|       const allConversations = document.querySelectorAll( | ||||
|         '.conversations-list .conversation' | ||||
|       ); | ||||
|       if (hasPressedAltAndMKey(e)) { | ||||
|         this.$refs.arrowDownButton.$el.click(); | ||||
|       } | ||||
|       if (hasPressedAltAndEKey(e)) { | ||||
|         const activeConversation = document.querySelector( | ||||
|           'div.conversations-list div.conversation.active' | ||||
|   | ||||
| @@ -50,10 +50,17 @@ | ||||
|         :show="showOptionsMenu" | ||||
|         @toggle-accounts="toggleAccountModal" | ||||
|         @show-support-chat-window="toggleSupportChatWindow" | ||||
|         @key-shortcut-modal="toggleKeyShortcutModal" | ||||
|         @close="toggleOptions" | ||||
|       /> | ||||
|     </div> | ||||
|  | ||||
|     <woot-key-shortcut-modal | ||||
|       v-if="showShortcutModal" | ||||
|       @close="closeKeyShortcutModal" | ||||
|       @clickaway="closeKeyShortcutModal" | ||||
|     /> | ||||
|  | ||||
|     <account-selector | ||||
|       :show-account-modal="showAccountModal" | ||||
|       @close-account-modal="toggleAccountModal" | ||||
| @@ -86,6 +93,9 @@ import OptionsMenu from './sidebarComponents/OptionsMenu.vue'; | ||||
| import AccountSelector from './sidebarComponents/AccountSelector.vue'; | ||||
| import AddAccountModal from './sidebarComponents/AddAccountModal.vue'; | ||||
| 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 { | ||||
|   components: { | ||||
| @@ -97,14 +107,16 @@ export default { | ||||
|     AccountSelector, | ||||
|     AddAccountModal, | ||||
|     AddLabelModal, | ||||
|     WootKeyShortcutModal, | ||||
|   }, | ||||
|   mixins: [adminMixin, alertMixin], | ||||
|   mixins: [adminMixin, alertMixin, eventListenerMixins], | ||||
|   data() { | ||||
|     return { | ||||
|       showOptionsMenu: false, | ||||
|       showAccountModal: false, | ||||
|       showCreateAccountModal: false, | ||||
|       showAddLabelModal: false, | ||||
|       showShortcutModal: false, | ||||
|     }; | ||||
|   }, | ||||
|  | ||||
| @@ -254,7 +266,19 @@ export default { | ||||
|     this.$store.dispatch('teams/get'); | ||||
|     this.setChatwootUser(); | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     toggleKeyShortcutModal() { | ||||
|       this.showShortcutModal = true; | ||||
|     }, | ||||
|     closeKeyShortcutModal() { | ||||
|       this.showShortcutModal = false; | ||||
|     }, | ||||
|     handleKeyEvents(e) { | ||||
|       if (hasPressedCommandAndForwardSlash(e)) { | ||||
|         this.toggleKeyShortcutModal(); | ||||
|       } | ||||
|     }, | ||||
|     toggleSupportChatWindow() { | ||||
|       window.$chatwoot.toggle(); | ||||
|     }, | ||||
|   | ||||
| @@ -26,6 +26,16 @@ | ||||
|             Contact Support | ||||
|           </woot-button> | ||||
|         </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> | ||||
|           <router-link | ||||
|             :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", | ||||
|     "SELECTOR_SUBTITLE": "Select an account from the following list", | ||||
|     "PROFILE_SETTINGS": "Profile Settings", | ||||
|     "KEYBOARD_SHORTCUTS": "Keyboard Shortcuts", | ||||
|     "LOGOUT": "Logout" | ||||
|   }, | ||||
|   "APP_GLOBAL": { | ||||
| @@ -159,5 +160,30 @@ | ||||
|       }, | ||||
|       "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; | ||||
| }; | ||||
|  | ||||
| export const hasPressedCommandAndForwardSlash = e => { | ||||
|   return e.metaKey && e.keyCode === 191; | ||||
| }; | ||||
|  | ||||
| export const hasPressedAltAndCKey = e => { | ||||
|   return e.altKey && e.keyCode === 67; | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sivin Varghese
					Sivin Varghese