fix(menu): make sure dropdown menu changes direction when screen is too
small Resolves https://github.com/go-vikunja/vikunja/issues/1523
This commit is contained in:
parent
f09b903153
commit
32501bc93b
|
|
@ -60,6 +60,7 @@
|
|||
v-if="project.maxPermission > PERMISSIONS.READ"
|
||||
class="menu-list-dropdown"
|
||||
:project="project"
|
||||
:simple="true"
|
||||
>
|
||||
<template #trigger="{toggleOpen}">
|
||||
<BaseButton
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@
|
|||
<div
|
||||
v-if="initialMount || open"
|
||||
v-show="open"
|
||||
ref="dropdownMenu"
|
||||
class="dropdown-menu"
|
||||
:style="dropdownMenuStyle"
|
||||
>
|
||||
<div class="dropdown-content">
|
||||
<slot :close="close" />
|
||||
|
|
@ -37,8 +39,9 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref} from 'vue'
|
||||
import {ref, nextTick, watch, computed} from 'vue'
|
||||
import {onClickOutside} from '@vueuse/core'
|
||||
import {computePosition, autoPlacement, offset, shift} from '@floating-ui/dom'
|
||||
import type {IconProp} from '@fortawesome/fontawesome-svg-core'
|
||||
|
||||
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
||||
|
|
@ -63,19 +66,53 @@ defineSlots<{
|
|||
'default': () => void
|
||||
}>()
|
||||
|
||||
|
||||
const initialMount = ref(false)
|
||||
const open = ref(false)
|
||||
const dropdown = ref<HTMLElement>()
|
||||
const dropdownMenu = ref<HTMLElement>()
|
||||
const dropdownPosition = ref({x: 0, y: 0})
|
||||
|
||||
function close() {
|
||||
open.value = false
|
||||
}
|
||||
|
||||
async function updatePosition() {
|
||||
if (!dropdown.value || !dropdownMenu.value) {
|
||||
return
|
||||
}
|
||||
|
||||
await nextTick()
|
||||
|
||||
const {x, y} = await computePosition(dropdown.value, dropdownMenu.value, {
|
||||
placement: 'bottom-end',
|
||||
middleware: [
|
||||
offset(4),
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-end', 'top-end', 'bottom-start', 'top-start'],
|
||||
padding: 8,
|
||||
}),
|
||||
shift({padding: 8}),
|
||||
],
|
||||
})
|
||||
|
||||
dropdownPosition.value = {x, y}
|
||||
}
|
||||
|
||||
const dropdownMenuStyle = computed(() => ({
|
||||
left: `${dropdownPosition.value.x}px`,
|
||||
top: `${dropdownPosition.value.y}px`,
|
||||
}))
|
||||
|
||||
function toggleOpen() {
|
||||
open.value = !open.value
|
||||
}
|
||||
|
||||
const dropdown = ref()
|
||||
watch(open, (isOpen) => {
|
||||
if (isOpen) {
|
||||
updatePosition()
|
||||
}
|
||||
})
|
||||
|
||||
onClickOutside(dropdown, (e) => {
|
||||
if (!open.value) {
|
||||
return
|
||||
|
|
@ -93,13 +130,9 @@ onClickOutside(dropdown, (e) => {
|
|||
|
||||
.dropdown-menu {
|
||||
min-inline-size: 12rem;
|
||||
padding-block-start: 4px;
|
||||
position: absolute;
|
||||
inset-block-start: 100%;
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
display: block;
|
||||
inset-inline-start: auto;
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
|
|
|
|||
|
|
@ -56,13 +56,14 @@
|
|||
{{ $t('menu.edit') }}
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
v-if="!simple"
|
||||
:to="{ name: 'project.settings.views', params: { projectId: project.id } }"
|
||||
icon="eye"
|
||||
>
|
||||
{{ $t('menu.views') }}
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
v-if="backgroundsEnabled"
|
||||
v-if="backgroundsEnabled && !simple"
|
||||
:to="{ name: 'project.settings.background', params: { projectId: project.id } }"
|
||||
icon="image"
|
||||
>
|
||||
|
|
@ -81,6 +82,7 @@
|
|||
{{ $t('menu.duplicate') }}
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
v-if="!simple"
|
||||
v-tooltip="isDefaultProject ? $t('menu.cantArchiveIsDefault') : ''"
|
||||
:to="{ name: 'project.settings.archive', params: { projectId: project.id } }"
|
||||
icon="archive"
|
||||
|
|
@ -139,9 +141,12 @@ import {useProjectStore} from '@/stores/projects'
|
|||
import {useAuthStore} from '@/stores/auth'
|
||||
import {PERMISSIONS} from '@/constants/permissions'
|
||||
|
||||
const props = defineProps<{
|
||||
const props = withDefaults(defineProps<{
|
||||
project: IProject
|
||||
}>()
|
||||
simple?: boolean
|
||||
}>(), {
|
||||
simple: false
|
||||
})
|
||||
|
||||
const projectStore = useProjectStore()
|
||||
const subscription = ref<ISubscription | null>(null)
|
||||
|
|
|
|||
Loading…
Reference in New Issue