2023-02-03 17:39:38 +00:00
|
|
|
<template>
|
|
|
|
<Menu as="div" class="relative inline-block text-left">
|
|
|
|
<div>
|
|
|
|
<slot name="trigger" :title="title">
|
|
|
|
<MenuButton
|
|
|
|
:class="[
|
|
|
|
'inline-flex w-full justify-center rounded-md bg-opacity-20 px-4 py-2',
|
|
|
|
'text-sm font-medium text-black hover:bg-opacity-30',
|
|
|
|
'focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-opacity-75',
|
|
|
|
buttonClass,
|
|
|
|
]"
|
|
|
|
>
|
|
|
|
<slot name="default">
|
|
|
|
{{ title }}
|
|
|
|
<ChevronDownIcon
|
|
|
|
class="ml-2 -mr-1 h-5 w-5"
|
|
|
|
aria-hidden="true"
|
|
|
|
v-if="!hideChevron"
|
|
|
|
/>
|
|
|
|
</slot>
|
|
|
|
</MenuButton>
|
|
|
|
</slot>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<transition
|
|
|
|
enter-active-class="transition duration-100 ease-out"
|
|
|
|
enter-from-class="transform scale-95 opacity-0"
|
|
|
|
enter-to-class="transform scale-100 opacity-100"
|
|
|
|
leave-active-class="transition duration-75 ease-in"
|
|
|
|
leave-from-class="transform scale-100 opacity-100"
|
|
|
|
leave-to-class="transform scale-95 opacity-0"
|
|
|
|
>
|
|
|
|
<MenuItems
|
|
|
|
:class="[
|
2023-02-04 11:34:50 +00:00
|
|
|
'absolute z-10 mt-2 w-56 divide-y divide-gray-100 rounded-md bg-white shadow-lg',
|
2023-02-03 17:39:38 +00:00
|
|
|
'ring-1 ring-black ring-opacity-5 focus:outline-none',
|
|
|
|
positionClass,
|
|
|
|
]"
|
|
|
|
>
|
|
|
|
<div class="px-1 py-1">
|
|
|
|
<MenuItem
|
|
|
|
as="template"
|
|
|
|
v-for="(option, index) of options"
|
|
|
|
:key="option.key || index"
|
|
|
|
v-slot="{ active }"
|
|
|
|
>
|
|
|
|
<slot name="option" :option="option" :active="active">
|
|
|
|
<RouterLink v-if="option.link" :to="option.link">
|
|
|
|
<MenuOption :active="active" :option="option" />
|
|
|
|
</RouterLink>
|
|
|
|
<MenuOption
|
|
|
|
v-else
|
|
|
|
:active="active"
|
|
|
|
:option="option"
|
|
|
|
@clicked="() => option.onClick?.()"
|
|
|
|
/>
|
|
|
|
</slot>
|
|
|
|
</MenuItem>
|
|
|
|
</div>
|
|
|
|
</MenuItems>
|
|
|
|
</transition>
|
|
|
|
</Menu>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue';
|
|
|
|
import { ChevronDownIcon } from '@heroicons/vue/24/outline';
|
2023-02-04 11:34:50 +00:00
|
|
|
import { computed } from 'vue';
|
|
|
|
import { RouterLink } from 'vue-router';
|
|
|
|
import { MenuOption as MenuOptionType } from './menu.interfaces';
|
2023-02-03 17:39:38 +00:00
|
|
|
import MenuOption from './MenuOption.vue';
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
title: string;
|
2023-02-04 11:34:50 +00:00
|
|
|
options: MenuOptionType[];
|
2023-02-03 17:39:38 +00:00
|
|
|
buttonClass?: string;
|
|
|
|
hideChevron?: boolean;
|
|
|
|
position?: 'left' | 'center' | 'right';
|
|
|
|
}>();
|
|
|
|
|
|
|
|
const positionClass = computed(() => {
|
2023-02-04 11:34:50 +00:00
|
|
|
if (!props.position || props.position === 'right')
|
|
|
|
return 'right-0 origin-top-right';
|
|
|
|
if (props.position === 'center')
|
|
|
|
return 'left-1/2 -translate-x-1/2 origin-top-center';
|
|
|
|
if (props.position === 'left') return 'left-0 origin-top-left';
|
2023-02-03 17:39:38 +00:00
|
|
|
return '';
|
|
|
|
});
|
|
|
|
</script>
|