mirror of
https://github.com/Lissy93/dashy.git
synced 2025-07-25 14:44:49 +02:00
✨ Adds context menu for more options on Settings
This commit is contained in:
parent
7ac233e763
commit
d3772891b5
@ -11,10 +11,12 @@
|
|||||||
@change="collapseChanged"
|
@change="collapseChanged"
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
>
|
>
|
||||||
<label :for="sectionKey" class="lbl-toggle" tabindex="-1">
|
<label :for="sectionKey" class="lbl-toggle" tabindex="-1"
|
||||||
|
@mouseup.right="openContextMenu" @contextmenu.prevent>
|
||||||
<Icon v-if="icon" :icon="icon" size="small" :url="title" class="section-icon" />
|
<Icon v-if="icon" :icon="icon" size="small" :url="title" class="section-icon" />
|
||||||
<h3>{{ title }}</h3>
|
<h3>{{ title }}</h3>
|
||||||
<EditModeIcon v-if="isEditMode" class="edit-mode-item" @click="openEditModal" />
|
<EditModeIcon v-if="isEditMode" @click="openEditModal"
|
||||||
|
v-tooltip="editTooltip()" class="edit-mode-item" />
|
||||||
</label>
|
</label>
|
||||||
<div class="collapsible-content">
|
<div class="collapsible-content">
|
||||||
<div class="content-inner">
|
<div class="content-inner">
|
||||||
@ -110,6 +112,13 @@ export default {
|
|||||||
openEditModal() {
|
openEditModal() {
|
||||||
this.$emit('openEditSection');
|
this.$emit('openEditSection');
|
||||||
},
|
},
|
||||||
|
openContextMenu(e) {
|
||||||
|
this.$emit('openContextMenu', e);
|
||||||
|
},
|
||||||
|
editTooltip() {
|
||||||
|
const content = this.$t('interactive-editor.edit-section.edit-tooltip');
|
||||||
|
return { content, trigger: 'hover focus', delay: { show: 100, hide: 0 } };
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -52,7 +52,7 @@ import Icon from '@/components/LinkItems/ItemIcon.vue';
|
|||||||
import ItemOpenMethodIcon from '@/components/LinkItems/ItemOpenMethodIcon';
|
import ItemOpenMethodIcon from '@/components/LinkItems/ItemOpenMethodIcon';
|
||||||
import StatusIndicator from '@/components/LinkItems/StatusIndicator';
|
import StatusIndicator from '@/components/LinkItems/StatusIndicator';
|
||||||
import EditItem from '@/components/InteractiveEditor/EditItem';
|
import EditItem from '@/components/InteractiveEditor/EditItem';
|
||||||
import ContextMenu from '@/components/LinkItems/ContextMenu';
|
import ContextMenu from '@/components/LinkItems/ItemContextMenu';
|
||||||
import StoreKeys from '@/utils/StoreMutations';
|
import StoreKeys from '@/utils/StoreMutations';
|
||||||
import { targetValidator } from '@/utils/ConfigHelpers';
|
import { targetValidator } from '@/utils/ConfigHelpers';
|
||||||
import EditModeIcon from '@/assets/interface-icons/interactive-editor-edit-mode.svg';
|
import EditModeIcon from '@/assets/interface-icons/interactive-editor-edit-mode.svg';
|
||||||
@ -186,7 +186,7 @@ export default {
|
|||||||
const lb1 = description && providerText ? '<br>' : '';
|
const lb1 = description && providerText ? '<br>' : '';
|
||||||
const hotkeyText = this.hotkey ? `<br>Press '${this.hotkey}' to launch` : '';
|
const hotkeyText = this.hotkey ? `<br>Press '${this.hotkey}' to launch` : '';
|
||||||
const tooltipText = providerText + lb1 + description + hotkeyText;
|
const tooltipText = providerText + lb1 + description + hotkeyText;
|
||||||
const editText = 'Click to Edit, or right-click for more options';
|
const editText = this.$t('interactive-editor.edit-section.edit-tooltip');
|
||||||
return {
|
return {
|
||||||
content: (this.isEditMode ? editText : tooltipText),
|
content: (this.isEditMode ? editText : tooltipText),
|
||||||
trigger: 'hover focus',
|
trigger: 'hover focus',
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
:color="displayData.color"
|
:color="displayData.color"
|
||||||
:customStyles="displayData.customStyles"
|
:customStyles="displayData.customStyles"
|
||||||
@openEditSection="openEditSection"
|
@openEditSection="openEditSection"
|
||||||
|
@openContextMenu="openContextMenu"
|
||||||
>
|
>
|
||||||
<div v-if="!items || items.length < 1" class="no-items">
|
<div v-if="!items || items.length < 1" class="no-items">
|
||||||
No Items to Show Yet
|
No Items to Show Yet
|
||||||
@ -51,6 +52,14 @@
|
|||||||
@closeEditSection="closeEditSection"
|
@closeEditSection="closeEditSection"
|
||||||
:sectionIndex="index"
|
:sectionIndex="index"
|
||||||
/>
|
/>
|
||||||
|
<ContextMenu
|
||||||
|
:show="contextMenuOpen"
|
||||||
|
:posX="contextPos.posX"
|
||||||
|
:posY="contextPos.posY"
|
||||||
|
:id="`context-menu-${groupId}`"
|
||||||
|
v-click-outside="closeContextMenu"
|
||||||
|
@openEditSection="openEditSection"
|
||||||
|
/>
|
||||||
</Collapsable>
|
</Collapsable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -59,6 +68,7 @@ import Item from '@/components/LinkItems/Item.vue';
|
|||||||
import Collapsable from '@/components/LinkItems/Collapsable.vue';
|
import Collapsable from '@/components/LinkItems/Collapsable.vue';
|
||||||
import IframeModal from '@/components/LinkItems/IframeModal.vue';
|
import IframeModal from '@/components/LinkItems/IframeModal.vue';
|
||||||
import EditSection from '@/components/InteractiveEditor/EditSection.vue';
|
import EditSection from '@/components/InteractiveEditor/EditSection.vue';
|
||||||
|
import ContextMenu from '@/components/LinkItems/SectionContextMenu.vue';
|
||||||
import ErrorHandler from '@/utils/ErrorHandler';
|
import ErrorHandler from '@/utils/ErrorHandler';
|
||||||
import StoreKeys from '@/utils/StoreMutations';
|
import StoreKeys from '@/utils/StoreMutations';
|
||||||
import { sortOrder as defaultSortOrder, localStorageKeys, modalNames } from '@/utils/defaults';
|
import { sortOrder as defaultSortOrder, localStorageKeys, modalNames } from '@/utils/defaults';
|
||||||
@ -76,6 +86,7 @@ export default {
|
|||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Collapsable,
|
Collapsable,
|
||||||
|
ContextMenu,
|
||||||
Item,
|
Item,
|
||||||
IframeModal,
|
IframeModal,
|
||||||
EditSection,
|
EditSection,
|
||||||
@ -83,6 +94,11 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
editMenuOpen: false,
|
editMenuOpen: false,
|
||||||
|
contextMenuOpen: false,
|
||||||
|
contextPos: {
|
||||||
|
posX: undefined,
|
||||||
|
posY: undefined,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -180,12 +196,26 @@ export default {
|
|||||||
this.editMenuOpen = true;
|
this.editMenuOpen = true;
|
||||||
this.$modal.show(modalNames.EDIT_SECTION);
|
this.$modal.show(modalNames.EDIT_SECTION);
|
||||||
this.$store.commit(StoreKeys.SET_MODAL_OPEN, true);
|
this.$store.commit(StoreKeys.SET_MODAL_OPEN, true);
|
||||||
|
this.contextMenuOpen = false;
|
||||||
},
|
},
|
||||||
closeEditSection() {
|
closeEditSection() {
|
||||||
this.editMenuOpen = false;
|
this.editMenuOpen = false;
|
||||||
this.$modal.hide(modalNames.EDIT_SECTION);
|
this.$modal.hide(modalNames.EDIT_SECTION);
|
||||||
this.$store.commit(StoreKeys.SET_MODAL_OPEN, false);
|
this.$store.commit(StoreKeys.SET_MODAL_OPEN, false);
|
||||||
},
|
},
|
||||||
|
/* Open custom context menu, and set position */
|
||||||
|
openContextMenu(e) {
|
||||||
|
this.contextMenuOpen = true;
|
||||||
|
if (e && window) {
|
||||||
|
this.contextPos = {
|
||||||
|
posX: e.clientX + window.pageXOffset,
|
||||||
|
posY: e.clientY + window.pageYOffset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeContextMenu() {
|
||||||
|
this.contextMenuOpen = false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
115
src/components/LinkItems/SectionContextMenu.vue
Normal file
115
src/components/LinkItems/SectionContextMenu.vue
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<transition name="slide">
|
||||||
|
<div class="context-menu" v-if="show && !isMenuDisabled"
|
||||||
|
:style="posX && posY ? `top:${posY}px;left:${posX}px;` : ''">
|
||||||
|
<!-- Open Options -->
|
||||||
|
<ul class="menu-section">
|
||||||
|
<li @click="openSection()">
|
||||||
|
<SameTabOpenIcon />
|
||||||
|
<span>{{ $t('context-menus.section.open-section') }}</span>
|
||||||
|
</li>
|
||||||
|
<li @click="openEditSectionMenu">
|
||||||
|
<EditIcon />
|
||||||
|
<span>{{ $t('context-menus.section.edit-section') }}</span>
|
||||||
|
</li>
|
||||||
|
<li v-if="isEditMode">
|
||||||
|
<MoveIcon />
|
||||||
|
<span>{{ $t('context-menus.section.move-section') }}</span>
|
||||||
|
</li>
|
||||||
|
<li v-if="isEditMode">
|
||||||
|
<BinIcon />
|
||||||
|
<span>{{ $t('context-menus.section.remove-section') }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Import icons for each element
|
||||||
|
import EditIcon from '@/assets/interface-icons/config-edit-json.svg';
|
||||||
|
import BinIcon from '@/assets/interface-icons/interactive-editor-remove.svg';
|
||||||
|
import MoveIcon from '@/assets/interface-icons/interactive-editor-move-to.svg';
|
||||||
|
import SameTabOpenIcon from '@/assets/interface-icons/open-current-tab.svg';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ContextMenu',
|
||||||
|
components: {
|
||||||
|
EditIcon,
|
||||||
|
MoveIcon,
|
||||||
|
BinIcon,
|
||||||
|
SameTabOpenIcon,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
posX: Number, // The X coordinate for positioning
|
||||||
|
posY: Number, // The Y coordinate for positioning
|
||||||
|
show: Boolean, // Should show or hide the menu
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isMenuDisabled() {
|
||||||
|
return !!this.$store.getters.appConfig.disableContextMenu;
|
||||||
|
},
|
||||||
|
isEditMode() {
|
||||||
|
return this.$store.state.editMode;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/* Called on item click, emits an event up to Item */
|
||||||
|
/* in order to launch the current app to a given target */
|
||||||
|
openSection() {
|
||||||
|
// TODO: Open Section
|
||||||
|
},
|
||||||
|
openEditSectionMenu() {
|
||||||
|
this.$emit('openEditSection');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
div.context-menu {
|
||||||
|
position: absolute;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
z-index: 8;
|
||||||
|
background: var(--context-menu-background);
|
||||||
|
color: var(--context-menu-color);
|
||||||
|
border: 1px solid var(--context-menu-secondary-color);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
box-shadow: var(--context-menu-shadow);
|
||||||
|
opacity: 0.98;
|
||||||
|
|
||||||
|
ul.menu-section {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px solid var(--context-menu-color);
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 1rem;
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px solid var(--context-menu-secondary-color);
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
width: 1rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
path { fill: currentColor; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define enter and leave transitions
|
||||||
|
.slide-enter-active { animation: slide-in .1s; }
|
||||||
|
.slide-leave-active { animation: slide-in .1s reverse; }
|
||||||
|
@keyframes slide-in {
|
||||||
|
0% { transform: scaleY(0.5) scaleX(0.8) translateY(-50px); }
|
||||||
|
100% { transform: scaleY(1) translateY(0) translateY(0); }
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user