base_ui/components/global/ContextMenu.vue

276 lines
7.5 KiB
Vue
Raw Permalink Normal View History

2025-02-01 09:34:55 +00:00
<template>
<div class="context-menu-dropdown">
<div class="dropdown">
<button
:data-offset="$attrs.dataOffset ?? undefined"
class="btn"
type="button"
id="context-menu"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<span class="tavasi tavasi-more-vert"></span>
</button>
<div
:style="{
width: $attrs.width ?? undefined,
height: $attrs.height ?? undefined,
'max-height': $attrs.maxHeight ?? '10rem',
}"
class="dropdown-menu"
aria-labelledby="context-menu"
>
<div v-for="(action, index) in contextMenu">
<div v-if="action.show">
<div v-if="action.can">
<button
v-if="!action.showOutside ?? true"
v-can="action.can"
class="dropdown-item"
type="button"
:key="index"
@click="handleAction(action)"
>
<!-- put below line if authorization is ok. -->
<!-- v-can="action.can" -->
<NuxtImg :src="prepareIcon(action)" alt="" class="img-fluid" />
{{ action.title }}
</button>
</div>
<div v-else>
<button
v-if="!action.showOutside ?? true"
class="dropdown-item"
type="button"
:key="index"
@click="handleAction(action)"
>
<!-- put below line if authorization is ok. -->
<!-- v-can="action.can" -->
<NuxtImg :src="prepareIcon(action)" alt="" class="img-fluid" />
{{ action.title }}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
/**
* @vue-prop {Array} list - لیست
* @vue-prop {*} clickedItem - آیتمی که کلیک شده است
* @vue-prop {*} contextMenu - منو که از سمت والد دریافت میگردد
* @vue-prop {*} parentComponent - کامپوننت والد
*/
export default {
// contextMenu: right click actions
// list: folder or file list.
// clickedItem: selected item in the loop.
props: ["list", "clickedItem", "contextMenu", "parentComponent"],
emits: [
"rename-item",
"remove-item",
"update-order",
"import",
"reply-to",
"filter",
"notifications",
"search",
"edit-item",
],
methods: {
/**
* آمادهسازی آیکون.
*
* @param {object} options - گزینههای آیکون
* @returns {string} - مسیر فایل SVG آیکون
*/
prepareIcon({ icon }) {
try {
return import(`assets/common/img/${icon}.svg`).default;
} catch (err) {
return import(`assets/common/img/icomoon/SVG/${icon}.svg`).default;
}
},
/**
* انجام اقدامات کلیک راست بر روی پوشه.
*
* انجام تمام اقدامات کلیک راست بر روی پوشه/فایل.
*
* @param {object} selectedAction - اقدام انتخابشده توسط کاربر
*/
handleAction(selectedAction) {
switch (selectedAction.action) {
case "search":
this.$emit("search");
break;
case "notifications":
this.$emit("notifications");
break;
case "filter":
this.$emit("filter");
break;
case "new-sub-folder":
this.$emit("new-sub-folder");
break;
case "remove":
this.$emit("remove-item");
break;
case "remove-item":
this.$emit("remove-item");
break;
case "rename":
this.toggleRenameForm(this.list, this.clickedItem);
this.$emit("rename-item");
break;
case "order":
this.$emit("update-order", selectedAction.value);
break;
case "move":
break;
case "details":
break;
case "copy":
this.$emit("copy-text");
break;
case "import":
this.$emit("import");
break;
case "export":
break;
case "archive":
break;
case "reply-to":
this.$emit("reply-to");
break;
case "edit-item":
this.$emit("edit-item");
break;
case "close":
this.$emit("close");
break;
case "join-to-group":
this.$emit("join-to-group");
break;
case "remove-from-lobby":
this.$emit("remove-from-lobby");
break;
case "subjecting":
this.$emit("subjecting");
break;
case "show-text":
this.$emit("show-text");
break;
default:
this.$emit("other", selectedAction.action);
}
},
/**
* نمایش/مخفی کردن فرم تغییر نام.
*
* نمایش یا مخفی کردن فرم تغییر نام در صورت انتخاب گزینه تغییر نام یا بستن فرم تغییر نام.
* 1- یافتن شاخص مورد انتخاب شده
* 2- بررسی اینکه آیتم وجود دارد یا خیر.
* 3- اگر آیتم وجود دارد، سپس تغییر وضعیت editMode را انجام میدهد
* 4- و در نهایت وضعیت editMode آیتم یافتشده را تنظیم میکند.
*
* @param {array} list - لیست پوشه یا فایل
* @param {object} clickedItem - پوشه/فایلی که کاربر میخواهد آن را تغییر نام دهد.
*/
toggleRenameForm(list, clickedItem) {
const resultIndex = list.findIndex((item) => clickedItem.id === item.id);
if (resultIndex > -1) {
const editMode = list[resultIndex]?.editMode ?? false;
this.$set(list[resultIndex], "editMode", !editMode);
this.$set(list[resultIndex], "parentComponent", this.parentComponent);
}
},
},
};
</script>
<style scoped lang="scss">
.context-menu-dropdown {
position: absolute;
left: 0;
top: 0;
height: 100%;
transition: all 0.3s ease;
display: flex;
align-items: center;
.dropdown {
.dropdown-menu {
width: 156px;
// max-height: 291px;
min-height: 5em;
height: auto;
max-height: 10rem;
border-radius: 10px;
background: #fff;
border: 1px solid #bac4ce;
overflow-y: auto;
padding: 1em;
z-index: 99;
//top: -3.5em !important;
left: 2.5em;
// height: 10rem;
.dropdown-item {
font-weight: normal;
font-size: 14px;
text-align: right;
color: #1b2733;
border: 1px solid rgba(0, 0, 0, 0);
padding: 0.2em 0;
&:hover,
&:focus {
background-color: #f0f0f0;
//font-weight: bold;
}
.img-fluid {
width: 1.8em;
}
}
}
.btn {
padding: 0;
display: flex;
align-items: center;
background: rgba(255, 255, 255, 0.8);
height: 100%;
&[aria-expanded="true"] {
.tavasi-more-vert:before {
content: "\e940";
color: #dc3545;
}
}
.tavasi {
// transition: all 0.2s;
// font-size: 20px;
// color: #6f6f6f;
}
&:hover .tavasi {
transform: scale(1.2);
// transition: all 0.2s;
// font-weight: bold;
}
}
}
}
</style>