feat: ability to add new shortcuts

This commit is contained in:
Fabio Di Stasio 2022-08-16 13:10:20 +02:00
parent 8cb2c197c8
commit d044a02cb7
9 changed files with 137 additions and 19 deletions

View File

@ -3,13 +3,18 @@ export const shortcutEvents: { [key: string]: { l18n: string; l18nParam?: string
'close-tab': { l18n: 'message.closeTab', context: 'tab' },
'next-tab': { l18n: 'message.nextTab', context: 'tab' },
'prev-tab': { l18n: 'message.previousTab', context: 'tab' },
'open-connections-modal': { l18n: 'message.allConnections' },
'toggle-console': { l18n: 'message.toggleConsole' }
'open-all-connections': { l18n: 'message.openAllConnections' },
'toggle-console': { l18n: 'message.toggleConsole' },
'save-content': { l18n: 'message.saveContent' },
'run-or-reload': { l18n: 'message.runOrReload' },
'create-connection': { l18n: 'message.createNewConnection' },
'open-settings': { l18n: 'message.openSettings' },
'open-scratchpad': { l18n: 'message.openScratchpad' }
};
interface ShortcutRecord {
event: string;
keys: Electron.Accelerator[];
keys: Electron.Accelerator[] | string[];
/** Needed for default shortcuts */
os: NodeJS.Platform[];
}
@ -18,6 +23,16 @@ interface ShortcutRecord {
* Default shortcuts
*/
const shortcuts: ShortcutRecord[] = [
{
event: 'run-or-reload',
keys: ['F5'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'save-content',
keys: ['CommandOrControl+S'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'open-new-tab',
keys: ['CommandOrControl+T'],
@ -49,7 +64,7 @@ const shortcuts: ShortcutRecord[] = [
os: ['linux', 'win32']
},
{
event: 'open-connections-modal',
event: 'open-all-connections',
keys: ['Shift+CommandOrControl+Space'],
os: ['darwin', 'linux', 'win32']
},

View File

@ -67,7 +67,7 @@ const { changeApplicationTheme } = settingsStore;
const isAllConnectionsModal: Ref<boolean> = ref(false);
ipcRenderer.on('open-connections-modal', () => {
ipcRenderer.on('open-all-connections', () => {
isAllConnectionsModal.value = true;
});

View File

@ -68,6 +68,10 @@ const props = defineProps({
disableAutofocus: {
type: Boolean,
default: false
},
closeOnConfirm: {
type: Boolean,
default: true
}
});
const emit = defineEmits(['confirm', 'hide']);
@ -90,7 +94,7 @@ const modalSizeClass = computed(() => {
const confirmModal = () => {
emit('confirm');
hideModal();
if (props.closeOnConfirm) hideModal();
};
const hideModal = () => {

View File

@ -1,10 +1,9 @@
<template>
<div class="form-group has-icon-right p-2 m-0">
<div class="form-group has-icon-right m-0">
<input
class="form-input"
type="text"
:value="pressedKeys"
readonly
:placeholder="t('message.registerAShortcut')"
@focus="isFocus = true"
@blur="isFocus = false"
@ -94,8 +93,9 @@ const onKey = (e: KeyboardEvent) => {
keyboardEvent.value = e;
};
watch(pressedKeys, () => {
emit('update:modelValue', pressedKeys.value);
watch(pressedKeys, (value) => {
if (value !== t('message.invalidShortcutMessage'))
emit('update:modelValue', pressedKeys.value);
});
watch(isFocus, (val) => {
@ -108,10 +108,13 @@ watch(isFocus, (val) => {
<style lang="scss" scoped>
.has-icon-right {
.form-input {
padding-right: 1.4rem;
padding-right: 1.8rem;
overflow: hidden;
text-overflow: ellipsis;
caret-color: transparent;
}
.form-icon {
right: 0.8rem;
right: 0.4rem;
}
}
</style>

View File

@ -1,8 +1,7 @@
<template>
<div class="p-relative">
<KeyPressDetector />
<div class="shortcuts-tools pb-2 px-2">
<button class="btn btn-dark btn-sm d-flex ml-2">
<button class="btn btn-dark btn-sm d-flex ml-2" @click="showAddModal">
<i class="mdi mdi-24px mdi-plus mr-1" /><span>{{ t('message.addShortcut') }}</span>
</button>
<button class="btn btn-dark btn-sm d-flex ml-2" @click="isConfirmRestoreModal = true">
@ -56,8 +55,43 @@
</div>
</div>
<Teleport to="#window-content">
<ConfirmModal
v-if="isConfirmAddModal"
:disable-autofocus="true"
:confirm-text="t('word.save')"
:close-on-confirm="false"
@confirm="addShortcut"
@hide="closeAddModal"
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-plus mr-1" /> {{ t('message.addShortcut') }}
</div>
</template>
<template #body>
<div class="mb-2">
<div class="form-group">
<label class="form-label">{{ t('word.event') }}</label>
<BaseSelect
v-model="shortcutToAdd.event"
class="form-select"
:options="eventOptions"
/>
</div>
</div>
<div class="mb-2">
<div class="form-group">
<label class="form-label">{{ t('word.key', 2) }}</label>
<KeyPressDetector v-model="typedShortcut" />
</div>
</div>
<small v-if="doesShortcutExists" class="text-warning">{{ t('message.shortcutAlreadyExists') }}</small>
</template>
</ConfirmModal>
<ConfirmModal
v-if="isConfirmDeleteModal"
:disable-autofocus="true"
@confirm="deleteShortcut"
@hide="isConfirmDeleteModal = false"
>
@ -74,6 +108,7 @@
</ConfirmModal>
<ConfirmModal
v-if="isConfirmRestoreModal"
:disable-autofocus="true"
@confirm="restoreDefaults"
@hide="isConfirmRestoreModal = false"
>
@ -91,7 +126,7 @@
</Teleport>
</template>
<script setup lang="ts">
import { Ref, ref } from 'vue';
import { Ref, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { useSettingsStore } from '@/stores/settings';
@ -99,18 +134,36 @@ import KeyPressDetector from './KeyPressDetector.vue';
import Application from '@/ipc-api/Application';
import { shortcutEvents, ShortcutRecord } from 'common/shortcuts';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import { computed } from '@vue/reactivity';
const { t } = useI18n();
const isMacOS = process.platform === 'darwin';
const isConfirmRestoreModal = ref(false);
const isConfirmAddModal = ref(false);
const isConfirmDeleteModal = ref(false);
const doesShortcutExists = ref(false);
const shortcutToAdd: Ref<ShortcutRecord> = ref({ event: undefined, keys: [], os: [process.platform] });
const typedShortcut = ref('');
const shortcutToDelete: Ref<ShortcutRecord> = ref(null);
const settingsStore = useSettingsStore();
const { shortcuts } = storeToRefs(settingsStore);
const eventOptions = computed(() => {
return Object.keys(shortcutEvents)
.map(key => {
return { value: key, label: t(shortcutEvents[key].l18n, { param: shortcutEvents[key].l18nParam }) };
})
.sort((a, b) => {
if (a.label < b.label) return -1;
if (a.label > b.label) return 1;
return 0;
});
});
const parseKeys = (keys: {[key: number]: string}[]) => {
return (keys as string[]).map(k => (
k.split('+')
@ -127,6 +180,27 @@ const restoreDefaults = () => {
return Application.restoreDefaultShortcuts();
};
const showAddModal = () => {
shortcutToAdd.value.event = eventOptions.value[0].value;
isConfirmAddModal.value = true;
};
const closeAddModal = () => {
typedShortcut.value = '';
doesShortcutExists.value = false;
shortcutToAdd.value = { event: undefined, keys: [], os: [process.platform] };
isConfirmAddModal.value = false;
};
const addShortcut = () => {
if (!typedShortcut.value.length || doesShortcutExists.value) return;
shortcutToAdd.value.keys = [typedShortcut.value.replaceAll(isMacOS ? '`Command' : 'Control', 'CommandOrControl')];
const filteredShortcuts = [shortcutToAdd.value, ...shortcuts.value];
isConfirmAddModal.value = false;
return Application.updateShortcuts(filteredShortcuts);
};
const showDeleteModal = (shortcut: ShortcutRecord) => {
isConfirmDeleteModal.value = true;
shortcutToDelete.value = shortcut;
@ -134,11 +208,20 @@ const showDeleteModal = (shortcut: ShortcutRecord) => {
const deleteShortcut = () => {
const filteredShortcuts = shortcuts.value.filter(s => (
shortcutToDelete.value.event !== s.event && shortcutToDelete.value.keys !== s.keys
shortcutToDelete.value.keys.toString() !== s.keys.toString()
));
Application.updateShortcuts(filteredShortcuts);
isConfirmDeleteModal.value = false;
return Application.updateShortcuts(filteredShortcuts);
};
watch(typedShortcut, () => {
doesShortcutExists.value = shortcuts.value.some(s => (
s.keys.some(k => (
k.replaceAll('CommandOrControl', isMacOS ? '`Command' : 'Control') === typedShortcut.value
))
));
});
</script>
<style lang="scss" scoped>
.table {

View File

@ -343,6 +343,7 @@ watch(selectedWorkspace, (newVal, oldVal) => {
text-align: left;
line-height: 1.1;
color: rgba($body-font-color-dark, 0.8);
text-align: center;
}
.settingbar-element-pin {

View File

@ -309,7 +309,13 @@ export const enUS = {
restoreDefaultsQuestion: 'Do you confirm to restore default values?',
registerAShortcut: 'Register a shortcut',
deleteShortcut: 'Delete shortcut',
invalidShortcutMessage: 'Invalid combination, continue to type'
invalidShortcutMessage: 'Invalid combination, continue to type',
shortcutAlreadyExists: 'Shortcut already exists',
saveContent: 'Save content',
openAllConnections: 'Open all connections',
openSettings: 'Open settings',
openScratchpad: 'Open scratchpad',
runOrReload: 'Run or reload'
},
faker: {
address: 'Address',

View File

@ -163,7 +163,8 @@
}
code {
background-color: #000;
background-color: #111;
border: 1px solid #444;
color: rgba($body-font-color-dark, 0.7);
}

View File

@ -209,6 +209,11 @@
}
}
code {
background-color: #eee;
border: 1px solid #ddd;
}
.workspace {
.workspace-explorebar {
background: $bg-color-light-gray;