Files
swingmusic-webclient/src/components/Contextmenu/ContextItem.vue
2023-03-26 18:06:15 +03:00

210 lines
4.1 KiB
Vue

<template>
<div
class="context-item"
@mouseenter="
option.children &&
childrenShowMode === contextChildrenShowMode.hover &&
showChildren()
"
@mouseleave="
option.children &&
childrenShowMode === contextChildrenShowMode.hover &&
hideChildren()
"
@click="runAction"
ref="parentRef"
>
<div class="icon image" :class="option.icon"></div>
<div class="label ellip">{{ option.label }}</div>
<div class="more image" v-if="option.children"></div>
<div
class="children rounded shadow-sm"
v-if="option.children"
ref="childRef"
>
<div
class="context-item"
v-for="child in option.children"
:key="child.label"
:class="[{ critical: child.critical }, child.type]"
@click="child.action && runChildAction(child.action)"
>
<div class="label ellip">
{{ child.label }}
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { createPopper, Instance } from "@popperjs/core";
import { ref } from "vue";
import { contextChildrenShowMode } from "@/composables/enums";
import { Option } from "@/interfaces";
const props = defineProps<{
option: Option;
childrenShowMode: contextChildrenShowMode;
}>();
const emit = defineEmits<{
(event: "hideContextMenu"): void;
}>();
const parentRef = ref<HTMLElement>();
const childRef = ref<HTMLElement>();
const childrenShown = ref(false);
let popperInstance: Instance | null = null;
function showChildren() {
if (childrenShown.value) {
childrenShown.value = false;
return;
}
popperInstance = createPopper(
parentRef.value as HTMLElement,
childRef.value as HTMLElement,
{
placement: "right-start",
modifiers: [
{
name: "offset",
options: {
offset: [-5, -2],
},
},
],
}
);
childRef.value ? (childRef.value.style.visibility = "visible") : null;
childrenShown.value = true;
}
function hideChildren() {
childRef.value ? (childRef.value.style.visibility = "hidden") : null;
popperInstance?.destroy();
childrenShown.value = false;
}
function hideContextMenu() {
if (props.option.children) return;
emit("hideContextMenu");
}
function runAction() {
if (props.option.children) {
if (childrenShown.value) {
hideChildren();
return;
}
showChildren();
return;
}
props.option.action && props.option.action();
hideContextMenu();
}
function runChildAction(action: () => void) {
action();
emit("hideContextMenu");
}
</script>
<style lang="scss">
.context-item {
width: 100%;
display: flex;
align-items: center;
padding: 0.4rem;
position: relative;
border-radius: $small;
.more {
height: 1.5rem;
width: 1.5rem;
position: absolute;
right: $small;
background-image: url("../../assets/icons/expand.svg");
}
.children {
position: absolute;
width: 12rem;
background-color: $context;
transform: scale(0);
padding: $medium;
border: solid 1px $gray;
.context-item {
padding: $small 1rem;
padding: 0.4rem;
}
.separator {
padding: 0;
}
}
&:hover {
background: $darkestblue;
}
.children {
transform: scale(0);
overflow: hidden;
max-height: calc(100vh - 10rem);
}
.icon {
height: 1.25rem;
width: 1.25rem;
margin-right: $small;
}
.label {
width: 9rem;
}
.folder {
background-image: url("../../assets/icons/folder.svg");
filter: invert(100%);
}
.artist {
background-image: url("../../assets/icons/artist.svg");
}
.album {
background-image: url("../../assets/icons/album.svg");
}
.delete {
background-image: url("../../assets/icons/delete.svg");
}
.plus {
background-image: url("../../assets/icons/plus.svg");
}
.play_next {
background-image: url("../../assets/icons/add_to_queue.svg");
}
.add_to_queue {
background-image: url("../../assets/icons/add-to-queue.svg");
transform: scale(0.8); // reason: icon is not from same source as other
}
.heart {
background-image: url("../../assets/icons/heart.svg");
}
}
</style>