Files
chopin-frontend/src/components/UI/Selector.vue
Raphix ea9cf2ce42
All checks were successful
Frontend Deployment / deploy-frontend (push) Successful in 35s
Version 1.2.0 - Ajout des suggestions et de paramètres
2025-09-07 18:18:54 +02:00

182 lines
3.9 KiB
Vue

<script setup>
import IconAction from './IconAction.vue';
import { ref, onMounted, watch, onUnmounted } from 'vue';
import { useSlots } from 'vue';
const slots = useSlots();
const boxWidth = ref(0);
const box = ref(null);
var slotsAll = slots.default ? slots.default() : [];
var allSlots = null
if(slotsAll.length > 0) {
if(typeof slotsAll[0].children !== "string") {
allSlots = slotsAll[0].children
} else {
allSlots = slotsAll
}
}
var firstSlot = allSlots[0] || null;
var otherSlots = allSlots.slice(1);
const showMenu = ref(false);
function selectOption(index) {
// Make it like a select
if (otherSlots[index]) {
const oldFirstSlot = firstSlot;
firstSlot = otherSlots[index];
otherSlots.splice(index, 1);
otherSlots.push(oldFirstSlot);
showMenu.value = false; // Hide the menu after selection
}
updateModelValue(firstSlot ? firstSlot.props ? firstSlot.props.value : '' : '');
}
const props = defineProps({
modelValue: String
});
const emit = defineEmits(['update:modelValue']);
function updateModelValue(value) {
emit('update:modelValue', value);
}
onMounted(() => {
window.addEventListener('rightclick', (e) => {
e.preventDefault(); // Prevent default context menu
});
window.addEventListener('click', (e) => {
hideMenu(e);
});
window.addEventListener('resize', () => {
showMenu.value = false;
});
updateModelValue(firstSlot ? firstSlot.props ? firstSlot.props.value : '' : '');
});
onUnmounted(() => {
window.removeEventListener('rightclick', (e) => {
e.preventDefault(); // Prevent default context menu
});
window.removeEventListener('click', (e) => {
hideMenu(e);
});
window.removeEventListener('resize', () => {
showMenu.value = false;
});
});
function hideMenu(e) {
// Check if the click is outside the context menu
if (box.value && !box.value.contains(e.target)) {
showMenu.value = false; // Hide context menu on click outside
}
}
defineExpose({
firstSlot: () => {
return firstSlot;
}
})
</script>
<template>
<section>
<div ref="box" :class="showMenu ? `showed firstbox` : 'firstbox'" @click="showMenu = !showMenu">
<template v-if="firstSlot">
<component style="white-space: break-spaces;" :is="firstSlot" />
</template>
<IconAction
class="icon"
:icon="showMenu ? 'fa-solid fa-angle-up' : 'fa-solid fa-angle-down'"
/>
</div>
<template v-if="otherSlots.length && showMenu">
<div class="container">
<div v-for="(slot, index) in otherSlots" :style="`width: ${box.offsetWidth - 10}px;`" class="option" @click="selectOption(index)" >
<component :is="slot" :key="index" />
</div>
</div>
</template>
</section>
</template>
<style scoped>
.firstbox {
background-color: var(--tertiary);
color: var(--text);
border: none;
border-radius: 5px;
padding: 5px;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
}
.container {
color: var(--text);
border: none;
border-radius: 0px 0px 5px 5px;
font-size: 14px;
display: flex;
flex-direction: column;
position: fixed;
justify-content: space-between;
user-select: none;
overflow-y: auto;
max-height: 16vh;
z-index: 4000;
}
.container .option:last-child {
border-radius: 0px 0px 5px 5px !important;
}
.container .option:only-child {
border-radius: 0px 0px 5px 5px !important;
}
.container .option:first-child {
border-top: 1px solid var(--secondary) !important;
}
.option {
width: 100%;
padding: 5px;
background-color: var(--tertiary);
cursor: pointer;
white-space: break-spaces;
}
.option:hover {
background-color: var(--primary-hover);
color: var(--text-inverse);
}
.showed {
/* margin-bottom: 0 !important;
padding-bottom: 0; */
border-radius: 5px 5px 0 0 !important;
}
.icon {
display: flex;
align-items: center;
}
</style>