diff options
Diffstat (limited to 'src/web/app/desktop/views/components/context-menu.vue')
| -rw-r--r-- | src/web/app/desktop/views/components/context-menu.vue | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/web/app/desktop/views/components/context-menu.vue b/src/web/app/desktop/views/components/context-menu.vue new file mode 100644 index 0000000000..9f5787e476 --- /dev/null +++ b/src/web/app/desktop/views/components/context-menu.vue @@ -0,0 +1,74 @@ +<template> +<div class="context-menu" :style="{ x: `${x}px`, y: `${y}px` }" @contextmenu.prevent="() => {}"> + <me-nu :menu="menu" @x="click"/> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import * as anime from 'animejs'; +import contains from '../../../common/scripts/contains'; +import meNu from './context-menu-menu.vue'; + +export default Vue.extend({ + components: { + 'me-nu': meNu + }, + props: ['x', 'y', 'menu'], + mounted() { + this.$nextTick(() => { + Array.from(document.querySelectorAll('body *')).forEach(el => { + el.addEventListener('mousedown', this.onMousedown); + }); + + this.$el.style.display = 'block'; + + anime({ + targets: this.$el, + opacity: [0, 1], + duration: 100, + easing: 'linear' + }); + }); + }, + methods: { + onMousedown(e) { + e.preventDefault(); + if (!contains(this.$el, e.target) && (this.$el != e.target)) this.close(); + return false; + }, + click(item) { + if (item.onClick) item.onClick(); + this.close(); + }, + close() { + Array.from(document.querySelectorAll('body *')).forEach(el => { + el.removeEventListener('mousedown', this.onMousedown); + }); + + this.$emit('closed'); + this.$destroy(); + } + } +}); +</script> + +<style lang="stylus" scoped> +.context-menu + $width = 240px + $item-height = 38px + $padding = 10px + + display none + position fixed + top 0 + left 0 + z-index 4096 + width $width + font-size 0.8em + background #fff + border-radius 0 4px 4px 4px + box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2) + opacity 0 + +</style> |