homemanager-fe/src/components/menu/Menu.vue

96 lines
2.9 KiB
Vue

<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="[
'absolute z-10 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg',
'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';
import { Component, computed } from 'vue';
import { RouteLocationRaw, RouterLink } from 'vue-router';
import MenuOption from './MenuOption.vue';
export interface MenuOption {
title: string;
key?: string;
link?: RouteLocationRaw;
icon?: Component;
onClick?: () => void;
component?: Component;
}
const props = defineProps<{
title: string;
options: MenuOption[];
buttonClass?: string;
hideChevron?: boolean;
position?: 'left' | 'center' | 'right';
}>();
const positionClass = computed(() => {
if (!props.position || props.position === 'right') return 'right-0';
if (props.position === 'center') return 'left-1/2 -translate-x-1/2';
if (props.position === 'left') return 'left-0';
return '';
});
</script>