filebrowser/frontend/src/components/ContextMenu.vue

247 lines
5.8 KiB
Vue

<template>
<div
id="context-menu"
ref="contextMenu"
v-show="showContext"
:style="{
top: `${top}px`,
left: `${left}px`,
}"
class="button no-select"
:class="{ 'dark-mode': isDarkMode, centered: centered }"
>
<div v-if="selectedCount > 0" class="button selected-count-header">
<span>{{ selectedCount }} selected</span>
</div>
<action
v-if="!isSearchActive"
icon="create_new_folder"
:label="$t('sidebar.newFolder')"
@action="showHover('newDir')"
/>
<action
v-if="!headerButtons.select && !isSearchActive"
icon="note_add"
:label="$t('sidebar.newFile')"
@action="showHover('newFile')"
/>
<action
v-if="!headerButtons.select && !isSearchActive"
icon="file_upload"
:label="$t('buttons.upload')"
@action="uploadFunc"
/>
<action
v-if="headerButtons.select"
icon="info"
:label="$t('buttons.info')"
show="info"
/>
<action
v-if="!isMultiple && !isSearchActive"
icon="check_circle"
:label="$t('buttons.selectMultiple')"
@action="toggleMultipleSelection"
/>
<action
v-if="headerButtons.download"
icon="file_download"
:label="$t('buttons.download')"
@action="startDownload"
:counter="selectedCount"
/>
<action
v-if="headerButtons.share"
icon="share"
:label="$t('buttons.share')"
show="share"
/>
<action
v-if="headerButtons.rename && !isSearchActive"
icon="mode_edit"
:label="$t('buttons.rename')"
show="rename"
/>
<action
v-if="headerButtons.copy"
icon="content_copy"
:label="$t('buttons.copyFile')"
show="copy"
/>
<action
v-if="headerButtons.move"
icon="forward"
:label="$t('buttons.moveFile')"
show="move"
/>
<action
v-if="headerButtons.delete"
icon="delete"
:label="$t('buttons.delete')"
show="delete"
/>
</div>
</template>
<script>
import downloadFiles from "@/utils/download";
import { state, getters, mutations } from "@/store"; // Import your custom store
import Action from "@/components/Action.vue";
export default {
name: "ContextMenu",
components: {
Action,
},
data() {
return {
posX: 0,
posY: 0,
};
},
computed: {
isSearchActive() {
return state.isSearchActive;
},
isMultiple() {
return state.multiple;
},
user() {
return state.user;
},
centered() {
return getters.isMobile() || !this.posX || !this.posY;
},
showContext() {
if (getters.currentPromptName() == "ContextMenu" && state.prompts != []) {
this.setPositions();
return true;
}
return false;
},
top() {
// Ensure the context menu stays within the viewport
return Math.min(
this.posY,
window.innerHeight - (this.$refs.contextMenu?.clientHeight ?? 0)
);
},
left() {
return Math.min(
this.posX,
window.innerWidth - (this.$refs.contextMenu?.clientWidth ?? 0)
);
},
isDarkMode() {
return getters.isDarkMode();
},
headerButtons() {
return {
select: state.selected.length > 0,
upload: state.user.perm?.create && state.selected.length > 0,
download: state.user.perm.download && state.selected.length > 0,
delete: state.selected.length > 0 && state.user.perm.delete,
rename: state.selected.length === 1 && state.user.perm.rename,
share: state.selected.length === 1 && state.user.perm.share,
move: state.selected.length > 0 && state.user.perm.rename,
copy: state.selected.length > 0 && state.user.perm?.create,
};
},
selectedCount() {
return getters.selectedCount();
},
},
methods: {
uploadFunc() {
mutations.showHover("upload");
},
showHover(value) {
return mutations.showHover(value);
},
setPositions() {
const contextProps = getters.currentPrompt().props;
let tempX = contextProps.posX;
let tempY = contextProps.posY;
// Assuming the screen width and height (adjust values based on your context)
const screenWidth = window.innerWidth; // or any fixed width depending on your app's layout
const screenHeight = window.innerHeight; // or any fixed height depending on your app's layout
// if x is too close to the right edge, move it to the left by 400px
if (tempX > screenWidth - 200) {
tempX -= 200;
}
// if y is too close to the bottom edge, move it up by 400px
if (tempY > screenHeight - 400) {
tempY -= 400;
}
this.posX = tempX;
this.posY = tempY;
},
toggleMultipleSelection() {
mutations.setMultiple(!state.multiple);
mutations.closeHovers();
},
startDownload() {
downloadFiles();
},
},
};
</script>
<style scoped>
#context-menu {
position: absolute;
z-index: 1000;
background-color: white;
max-width: 20em;
min-width: 15em;
min-height: 4em;
height: auto;
display: flex;
flex-direction: column;
justify-content: center;
}
#context-menu.centered {
top: 50% !important;
left: 50% !important;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.selected-count-header {
border-radius: 0.5em;
cursor: unset;
margin-bottom: 0.5em;
}
#context-menu .action {
width: auto;
display: flex;
align-items: center;
}
#context-menu > span {
display: inline-block;
margin-left: 1em;
color: #6f6f6f;
margin-right: auto;
}
#context-menu .action span {
display: none;
}
/* File selection */
#context-menu.dark-mode {
background: var(--surfaceSecondary) !important;
}
#context-menu.dark-mode span {
color: var(--textPrimary) !important;
}
</style>