diff --git a/client/dive-common/components/ActionEditors/ActionShortcuts.vue b/client/dive-common/components/ActionEditors/ActionShortcuts.vue index 0dd20c58..f08b620b 100644 --- a/client/dive-common/components/ActionEditors/ActionShortcuts.vue +++ b/client/dive-common/components/ActionEditors/ActionShortcuts.vue @@ -4,9 +4,11 @@ import { computed, defineComponent, ref, Ref, } from 'vue'; +import draggable from 'vuedraggable'; import { DIVEAction, DIVEActionShortcut, TrackSelectAction, } from 'dive-common/use/useActions'; +import { ButtonShortcut } from 'vue-media-annotator/use/AttributeTypes'; import { useAttributes, useConfiguration, useTrackStyleManager, } from 'vue-media-annotator/provides'; @@ -22,6 +24,7 @@ export default defineComponent({ GetShortcut, ActionEditor, ButtonShortcutEditor, + draggable, }, props: { disabled: { @@ -40,6 +43,8 @@ export default defineComponent({ tempList.push(item); }); shortcutList.value = tempList; + } else { + shortcutList.value = []; } }; updateShortCutList(); @@ -55,6 +60,31 @@ export default defineComponent({ actionList.value = editingShortcut.value?.actions || []; }; + const getShortcutDisplay = (item: DIVEActionShortcut) => { + const { key, modifiers } = item.shortcut; + if (!key) { + return ''; + } + if (modifiers?.length) { + return `${key}+${modifiers.join('+')}`; + } + return key; + }; + + const hasKeyboardShortcut = (item: DIVEActionShortcut) => !!(item.shortcut.key && item.shortcut.key.length); + + const isIconOnlyButton = (button: ButtonShortcut) => { + const hasText = !!(button.buttonText && button.buttonText.trim()); + return !hasText && !!(button.iconPrepend || button.iconAppend); + }; + + const onShortcutOrderEnd = () => { + if (!configMan.configuration.value) { + configMan.configuration.value = {}; + } + configMan.configuration.value.shortcuts = [...shortcutList.value]; + }; + const editShortcut = (index?: number) => { addEditShortcut.value = true; if (index !== undefined) { @@ -188,6 +218,10 @@ export default defineComponent({ addEditActionindex, saveAction, saveShortcutDisabled, + getShortcutDisplay, + hasKeyboardShortcut, + isIconOnlyButton, + onShortcutOrderEnd, }; }, @@ -220,78 +254,140 @@ export default defineComponent({ Add Shortcut - - - - mdi-keyboard-outlineKeyboard - - - - - mdi-button-cursorButton - - - - - Description - - - - - Actions - - - - - Edit - - - - - - - mdi-keyboard-outline{{ item.shortcut.key }}{{ item.shortcut.modifiers && item.shortcut.modifiers.length ? `+${item.shortcut.modifiers.join('+')}` : '' }} - + + Drag - - - mdi-button-cursor - {{ item.button.iconPrepend }} - {{ item.button.buttonText }} - {{ item.button.iconAppend }} - + + Shortcut - - {{ item.description }} + + Button - - - {{ action.action.type }} - + + Description - - - mdi-pencil - - - mdi-delete - + + Actions + + + Edit + + + + + mdi-drag + + + + + + + No keyboard shortcut + + + + + + Custom UI button + + + + + {{ item.description || '—' }} + + + + {{ action.action.type }} + + + + + + mdi-pencil + + + + + mdi-delete + + + + +
@@ -477,4 +573,22 @@ export default defineComponent({ min-height: 15px; max-height: 15px; } + + .drag-handle { + cursor: grab; + } + + .action-shortcut-list-row { + border-bottom: 1px solid rgba(128, 128, 128, 0.2); + } + + .shortcut-button-preview--icon-only { + min-width: 28px !important; + padding: 0 6px !important; + + .v-icon { + margin-left: 0 !important; + margin-right: 0 !important; + } + } diff --git a/client/dive-common/components/Attributes/AttributeEditor.vue b/client/dive-common/components/Attributes/AttributeEditor.vue index 3cf0414a..1459108d 100644 --- a/client/dive-common/components/Attributes/AttributeEditor.vue +++ b/client/dive-common/components/Attributes/AttributeEditor.vue @@ -535,6 +535,8 @@ export default defineComponent({ diff --git a/client/dive-common/components/Attributes/AttributeShortcuts.vue b/client/dive-common/components/Attributes/AttributeShortcuts.vue index 8ad107d4..bfc194b3 100644 --- a/client/dive-common/components/Attributes/AttributeShortcuts.vue +++ b/client/dive-common/components/Attributes/AttributeShortcuts.vue @@ -3,6 +3,7 @@ import { computed, defineComponent, ref, PropType, Ref, watch, } from 'vue'; +import draggable from 'vuedraggable'; import { AttributeShortcut, ButtonShortcut } from 'vue-media-annotator/use/AttributeTypes'; import usedShortcuts from 'dive-common/use/usedShortcuts'; import { useAttributes } from 'vue-media-annotator/provides'; @@ -13,6 +14,7 @@ export default defineComponent({ name: 'AttributeShortcuts', components: { ButtonShortcutEditor, + draggable, }, props: { value: { @@ -23,6 +25,14 @@ export default defineComponent({ type: String as PropType<'text' | 'number' | 'boolean'>, required: true, }, + attributeName: { + type: String, + default: '', + }, + attributeColor: { + type: String, + default: '', + }, }, setup(props, { emit }) { const editShortcutDialog = ref(false); @@ -74,10 +84,31 @@ export default defineComponent({ return `${base}${shorcut.key}`; }; + const defaultDescription = (type: AttributeShortcut['type']) => { + if (type === 'remove') { + return 'Remove the value'; + } + return 'Set the Value'; + }; + + const isDefaultDescription = (description: string) => [ + 'Set the Value', + 'Remove the value', + 'Enter a Description', + '', + ].includes(description); + + const hasKeyboardShortcut = (shortcut: AttributeShortcut) => !!(shortcut.key && shortcut.key.length); + + const isIconOnlyButton = (button: ButtonShortcut) => { + const hasText = !!(button.buttonText && button.buttonText.trim()); + return !hasText && !!(button.iconPrepend || button.iconAppend); + }; + const editShortcut = (shortcut: AttributeShortcut, index: number) => { selectedShortcut.value = index; selectedShortcutType.value = shortcut.type; - selectedShortcutDescription.value = shortcut.description || 'Enter a Description'; + selectedShortcutDescription.value = shortcut.description || defaultDescription(shortcut.type); selectedShortcutValue.value = shortcut.value || 0; selectedShortcutKey.value = getShortcutDisplay(shortcut); selectedShortcutButton.value = shortcut.button || undefined; @@ -125,7 +156,7 @@ export default defineComponent({ const addShortcut = () => { selectedShortcut.value = props.value.length; selectedShortcutType.value = 'set'; - selectedShortcutDescription.value = 'Enter a Description'; + selectedShortcutDescription.value = defaultDescription('set'); if (props.valueType === 'boolean') { selectedShortcutValue.value = false; } @@ -223,6 +254,15 @@ export default defineComponent({ } }); + watch(selectedShortcutType, (type) => { + if (!editShortcutDialog.value) { + return; + } + if (isDefaultDescription(selectedShortcutDescription.value)) { + selectedShortcutDescription.value = defaultDescription(type); + } + }); + const selectedDisplayKey = computed(() => { let base = ''; if (selectedShortcutModifiers.value.length) { @@ -231,6 +271,15 @@ export default defineComponent({ } return `${base}${selectedShortcutKey.value}`; }); + + const onShortcutOrderEnd = () => { + emit('input', copy.value); + }; + + watch(() => props.value, (val) => { + copy.value = val; + }); + return { editShortcutDialog, selectedShortcutType, @@ -247,6 +296,8 @@ export default defineComponent({ awaitingKeyPress, shortcutError, getShortcutDisplay, + hasKeyboardShortcut, + isIconOnlyButton, cancel, save, addShortcut, @@ -254,54 +305,166 @@ export default defineComponent({ editShortcut, editKeyPress, copy, + onShortcutOrderEnd, }; }, }); -awaitingKeyPress +