Fix dropdowns

This commit is contained in:
wvffle 2022-07-22 00:23:45 +00:00 committed by Georg Krause
parent 232f0ff465
commit a7f4df68ea
4 changed files with 39 additions and 51 deletions

View File

@ -14,6 +14,7 @@ import { computed, ref, watch, watchEffect, onMounted } from 'vue'
import { useGettext } from 'vue3-gettext' import { useGettext } from 'vue3-gettext'
import { useStore } from '~/store' import { useStore } from '~/store'
import { setupDropdown } from '~/utils/fomantic' import { setupDropdown } from '~/utils/fomantic'
import { useCurrentElement } from '@vueuse/core'
interface Props { interface Props {
width: number width: number
@ -104,19 +105,14 @@ watch(languageSelection, (v) => {
store.dispatch('ui/currentLanguage', v) store.dispatch('ui/currentLanguage', v)
}) })
watch(() => store.state.auth.authenticated, (authenticated) => { const el = useCurrentElement()
if (authenticated) { watchEffect(() => {
setupDropdown('.admin-dropdown')
}
setupDropdown('.user-dropdown')
}, { immediate: true })
watch(() => store.state.auth.availablePermissions, () => {
if (store.state.auth.authenticated) { if (store.state.auth.authenticated) {
setupDropdown('.admin-dropdown') setupDropdown('.admin-dropdown', el.value)
} }
}, { immediate: true })
setupDropdown('.user-dropdown', el.value)
})
onMounted(() => { onMounted(() => {
document.getElementById('fake-sidebar')?.classList.add('loaded') document.getElementById('fake-sidebar')?.classList.add('loaded')

View File

@ -2,12 +2,12 @@
import type { Track, Artist, Album, Playlist, Library, Channel, Actor } from '~/types' import type { Track, Artist, Album, Playlist, Library, Channel, Actor } from '~/types'
import type { PlayOptionsProps } from '~/composables/audio/usePlayOptions' import type { PlayOptionsProps } from '~/composables/audio/usePlayOptions'
import { ref, computed, watch, nextTick } from 'vue' import { ref, computed, onMounted } from 'vue'
import { useGettext } from 'vue3-gettext' import { useGettext } from 'vue3-gettext'
import usePlayOptions from '~/composables/audio/usePlayOptions' import usePlayOptions from '~/composables/audio/usePlayOptions'
import useReport from '~/composables/moderation/useReport' import useReport from '~/composables/moderation/useReport'
import { useCurrentElement } from '@vueuse/core' import { useCurrentElement } from '@vueuse/core'
import { setupDropdown, getDropdown } from '~/utils/fomantic' import { setupDropdown } from '~/utils/fomantic'
interface Props extends PlayOptionsProps { interface Props extends PlayOptionsProps {
dropdownIconClasses?: string[] dropdownIconClasses?: string[]
@ -63,8 +63,6 @@ const {
const { report, getReportableObjects } = useReport() const { report, getReportableObjects } = useReport()
const clicked = ref(false)
const { $pgettext } = useGettext() const { $pgettext } = useGettext()
const labels = computed(() => ({ const labels = computed(() => ({
playNow: $pgettext('*/Queue/Dropdown/Button/Title', 'Play now'), playNow: $pgettext('*/Queue/Dropdown/Button/Title', 'Play now'),
@ -93,29 +91,31 @@ const title = computed(() => {
if (props.track) { if (props.track) {
return $pgettext('*/Queue/Button/Title', 'This track is not available in any library you have access to') return $pgettext('*/Queue/Button/Title', 'This track is not available in any library you have access to')
} }
return ''
}) })
watch(clicked, async () => { const el = useCurrentElement()
await setupDropdown() const dropdown = ref()
onMounted(() => {
dropdown.value = setupDropdown('.ui.dropdown', el.value)
})
getDropdown().dropdown('show', function () { const openMenu = () => {
// little magic to ensure the menu is always visible in the viewport // little magic to ensure the menu is always visible in the viewport
// By default, try to diplay it on the right if there is enough room // By default, try to diplay it on the right if there is enough room
const menu = getDropdown().find('.menu') const menu = dropdown.value.find('.menu')
const viewportOffset = menu.get(0)?.getBoundingClientRect() ?? { right: 0, left: 0 } const viewportOffset = menu.get(0)?.getBoundingClientRect() ?? { right: 0, left: 0 }
const viewportWidth = document.documentElement.clientWidth const viewportWidth = document.documentElement.clientWidth
const rightOverflow = viewportOffset.right - viewportWidth const rightOverflow = viewportOffset.right - viewportWidth
const leftOverflow = -viewportOffset.left const leftOverflow = -viewportOffset.left
let offset = 0
if (rightOverflow > 0) { if (rightOverflow > 0) {
offset = -rightOverflow - 5 menu.css({ cssText: `left: ${-rightOverflow - 5}px !important;` })
menu.css({ cssText: `left: ${offset}px !important;` })
} else if (leftOverflow > 0) { } else if (leftOverflow > 0) {
offset = leftOverflow + 5 menu.css({ cssText: `right: -${leftOverflow + 5}px !important;` })
menu.css({ cssText: `right: -${offset}px !important;` }) }
} }
})
})
</script> </script>
<template> <template>
@ -143,16 +143,13 @@ watch(clicked, async () => {
<button <button
v-if="!discrete && !iconOnly" v-if="!discrete && !iconOnly"
:class="['ui', {disabled: !playable && !filterableArtist}, 'floating', 'dropdown', {'icon': !dropdownOnly}, {'button': !dropdownOnly}]" :class="['ui', {disabled: !playable && !filterableArtist}, 'floating', 'dropdown', {'icon': !dropdownOnly}, {'button': !dropdownOnly}]"
@click.stop.prevent="clicked = true" @click.stop.prevent="openMenu"
> >
<i <i
:class="dropdownIconClasses.concat(['icon'])" :class="dropdownIconClasses.concat(['icon'])"
:title="title" :title="title"
/> />
<div <div class="menu">
v-if="clicked"
class="menu"
>
<button <button
class="item basic" class="item basic"
data-ref="enqueue" data-ref="enqueue"

View File

@ -7,5 +7,5 @@ export const install: InitModule = ({ app, store }) => {
store.commit('ui/pageTitle', binding.value) store.commit('ui/pageTitle', binding.value)
}) })
app.directive('dropdown', setupDropdown) app.directive('dropdown', (element) => setupDropdown(element))
} }

View File

@ -1,17 +1,10 @@
/// <reference types="semantic-ui" /> /// <reference types="semantic-ui" />
import $ from 'jquery' import $ from 'jquery'
import { tryOnMounted, useCurrentElement } from '@vueuse/core'
export const getDropdown = (selector = '.ui.dropdown'): JQuery => { export const setupDropdown = (selector: string | HTMLElement = '.ui.dropdown', el: Element = document.body) => {
const el = useCurrentElement()
return $(el.value).find(selector)
}
export const setupDropdown = (selector: string | HTMLElement = '.ui.dropdown') => tryOnMounted(() => {
const el = useCurrentElement()
const $dropdown = typeof selector === 'string' const $dropdown = typeof selector === 'string'
? $(el.value).find(selector) ? $(el).find(selector)
: $(selector) : $(selector)
$dropdown.dropdown({ $dropdown.dropdown({
@ -24,4 +17,6 @@ export const setupDropdown = (selector: string | HTMLElement = '.ui.dropdown') =
$dropdown.dropdown('hide') $dropdown.dropdown('hide')
} }
}) })
}, false)
return $dropdown
}