Files
sera-new-hp/components/DropDown.vue

164 lines
3.6 KiB
Vue

<script setup lang="ts">
import {
DropDownAlignment,
type DropDownProperty,
} from "~/utils/types/dropDown";
const property = defineProps<DropDownProperty>();
const isOpen = ref<boolean>(false);
const listAlignment = ref<typeof DropDownAlignment | number>(
property.alignment as DropDownAlignment | DropDownAlignment.Left
);
const alignmentClass = computed(() => ({
"left-aligned-list": listAlignment.value === DropDownAlignment.Left,
"right-aligned-list": listAlignment.value === DropDownAlignment.Right,
}));
const handleMouseHoverEvent = (event: Event) => {
const eventType = event.type;
if (property.mode !== DropDownMode.onMouseHover) return;
if (eventType === "mouseover") {
isOpen.value = true;
} else if (eventType === "mouseleave") {
isOpen.value = false;
}
return;
};
const handleClickEvent = () => {
if (property.mode !== DropDownMode.onClick) return;
isOpen.value = !isOpen.value;
return;
};
const handleFocusOutEvent = () => {
if (property.mode !== DropDownMode.onClick) return;
isOpen.value = false;
return;
};
</script>
<template>
<div
class="dropdown-menu"
:class="alignmentClass"
v-on="{
mouseover: handleMouseHoverEvent,
mouseleave: handleMouseHoverEvent,
}"
>
<button
class="dropdown-label"
v-on="{
click: handleClickEvent,
focusout: handleFocusOutEvent,
}"
>
{{ property.label }}
</button>
<Transition name="dropdown-fade">
<div class="dropdown-item-list" v-if="isOpen">
<ul>
<li
v-for="entry in property.entries"
:key="property.entries.indexOf(entry)"
>
<NuxtLink :to="entry.link">{{ entry.text }}</NuxtLink>
</li>
</ul>
</div>
</Transition>
</div>
</template>
<style scoped>
.dropdown-fade-enter-active,
.dropdown-fade-leave-active {
transition: opacity 0.2s ease;
}
.dropdown-fade-enter-from,
.dropdown-fade-leave-to {
opacity: 0;
}
.dropdown-menu {
display: inline-block;
width: fit-content;
position: relative;
}
.dropdown-label {
background: none;
width: fit-content;
padding: 1rem 2rem;
border: transparent solid 3px;
font-size: 1em;
font-weight: bold;
color: var(--neptune1);
}
.dropdown-label:hover {
cursor: pointer;
color: var(--andromeda);
border-top: currentColor solid 3px;
transition: 0.2s linear;
}
.left-aligned-list {
text-align: left;
& .dropdown-item-list {
left: 0;
}
}
.right-aligned-list {
text-align: right;
& .dropdown-item-list {
right: 0;
text-align: left;
}
}
.dropdown-item-list {
display: block;
background: var(--neptune1);
color: var(--starlight);
font-weight: bold;
position: absolute;
top: auto;
z-index: 100;
min-width: 100%;
width: fit-content;
text-wrap: nowrap;
& ul {
list-style: none;
padding: 0 0.25rem;
}
& ul li {
margin: 0.5rem 0;
transition: 0.2s linear;
}
& ul li:first-child {
margin-top: 0;
}
& ul li:last-child {
margin-bottom: 0;
}
& ul li a {
display: block;
width: 100%;
text-decoration: none;
color: currentColor;
padding: 0 0.5rem;
}
& ul li:hover a {
text-decoration: currentColor underline dashed;
text-decoration-thickness: 2px;
}
}
</style>