scinote-web/app/javascript/vue/shared/menu_dropdown.vue

114 lines
4 KiB
Vue
Raw Normal View History

<template>
2023-11-24 18:08:28 +08:00
<div class="relative" v-if="listItems.length > 0 || alwaysShow" v-click-outside="closeMenu" >
2023-12-05 03:59:16 +08:00
<button ref="field" :class="btnClasses" @click="isOpen = !isOpen">
<i v-if="btnIcon" :class="btnIcon"></i>
{{ btnText }}
2023-12-05 03:59:16 +08:00
<i v-if="caret && isOpen" class="sn-icon sn-icon-up"></i>
<i v-else-if="caret" class="sn-icon sn-icon-down"></i>
</button>
2023-12-05 03:59:16 +08:00
<teleport to="body">
<div ref="flyout"
2024-01-12 00:42:17 +08:00
v-if="isOpen"
2023-12-05 03:59:16 +08:00
class="fixed z-[3000] bg-sn-white inline-block rounded p-2.5 sn-shadow-menu-sm flex flex-col gap-[1px]"
:class="{
'right-0': position === 'right',
'left-0': position === 'left',
}"
>
<span v-for="(item, i) in listItems" :key="i" class="contents">
<div v-if="item.dividerBefore" class="border-0 border-t border-solid border-sn-light-grey"></div>
<a :href="item.url" v-if="!item.submenu"
:target="item.url_target || '_self'"
:class="{ 'bg-sn-super-light-blue': item.active }"
2023-12-05 03:59:16 +08:00
:data-toggle="item.modalTarget && 'modal'"
:data-target="item.modalTarget"
class="block whitespace-nowrap rounded px-3 py-2.5 hover:!text-sn-blue hover:no-underline cursor-pointer hover:bg-sn-super-light-grey leading-5"
@click="handleClick($event, item)"
2023-09-24 01:15:35 +08:00
>
{{ item.text }}
2023-12-05 03:59:16 +08:00
</a>
<div v-else class="-mx-2.5 px-2.5 group relative">
<span
:class="{ 'bg-sn-super-light-blue': item.active }"
class="flex group items-center rounded relative text-sn-blue whitespace-nowrap px-3 py-2.5 hover:no-underline cursor-pointer
group-hover:bg-sn-super-light-blue hover:!bg-sn-super-light-grey"
2023-12-05 03:59:16 +08:00
>
{{ item.text }}
<i class="sn-icon sn-icon-right ml-auto"></i>
</span>
<div
2024-01-11 22:40:03 +08:00
class="absolute bg-sn-white top-0 rounded p-2.5 sn-shadow-menu-sm flex flex-col gap-[1px] tw-hidden group-hover:block"
2023-12-05 03:59:16 +08:00
:class="{
'left-0 ml-[100%]': item.position === 'right',
2024-01-11 22:40:03 +08:00
'right-0 mr-[100%]': item.position === 'left'
2023-12-05 03:59:16 +08:00
}"
>
2023-12-05 03:59:16 +08:00
<a v-for="(sub_item, si) in item.submenu" :key="si"
:href="sub_item.url"
:traget="sub_item.url_target || '_self'"
:class="{ 'bg-sn-super-light-blue': item.active }"
class="block whitespace-nowrap rounded px-3 py-2.5 hover:!text-sn-blue hover:no-underline cursor-pointer hover:bg-sn-super-light-grey leading-5"
@click="handleClick($event, sub_item)"
>
{{ sub_item.text }}
</a>
</div>
</div>
2023-12-05 03:59:16 +08:00
</span>
</div>
</teleport>
</div>
</template>
<script>
2024-01-11 22:40:03 +08:00
import { vOnClickOutside } from '@vueuse/components';
2023-12-05 03:59:16 +08:00
import FixedFlyoutMixin from './mixins/fixed_flyout.js';
export default {
name: 'DropdownMenu',
props: {
listItems: { type: Array, default: () => [] },
position: { type: String, default: 'left' },
btnClasses: { type: String, default: 'btn btn-light' },
btnText: { type: String, required: false },
btnIcon: { type: String, required: false },
caret: { type: Boolean, default: false },
2023-11-10 20:34:36 +08:00
alwaysShow: { type: Boolean, default: false }
},
data() {
return {
2023-12-05 03:59:16 +08:00
isOpen: false
};
},
2023-11-09 19:40:06 +08:00
directives: {
'click-outside': vOnClickOutside
},
2023-12-05 03:59:16 +08:00
mixins: [FixedFlyoutMixin],
methods: {
closeMenu() {
2023-12-05 03:59:16 +08:00
this.isOpen = false;
},
closeMenuAndEmit(event) {
const isClickInsideModal = event.target.closest('.modal');
if (!isClickInsideModal) {
this.showMenu = false;
this.$emit('menu-visibility-changed', false);
}
},
handleClick(event, item) {
if (!item.url) {
event.preventDefault();
}
if (item.emit) {
2023-12-01 07:01:08 +08:00
this.$emit(item.emit, item.params);
this.$emit('dtEvent', item.emit, item);
}
this.closeMenu();
}
}
};
</script>