Fix dropdown

This commit is contained in:
Julien Nahum 2023-12-20 13:42:43 +01:00
parent 933f95e944
commit df2fa4c444
7 changed files with 65 additions and 69 deletions

View File

@ -1,54 +1,50 @@
<template> <template>
<div class="relative"> <div class="relative" ref="dropdown">
<slot name="trigger" <slot name="trigger"
:toggle="toggle" :toggle="toggle"
:open="open" :open="open"
:close="close" :close="close"
/> />
<collapsible v-model="isOpen" :class="dropdownClass"> <collapsible v-model="isOpen" :class="dropdownClass" @click-away="onClickAway">
<div class="py-1 " role="menu" aria-orientation="vertical" aria-labelledby="options-menu"> <div class="py-1 " role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
<slot /> <slot/>
</div> </div>
</collapsible> </collapsible>
</div> </div>
</template> </template>
<script> <script setup>
import { ref } from 'vue' import {ref} from 'vue'
import Collapsible from './transitions/Collapsible.vue' import Collapsible from './transitions/Collapsible.vue'
export default { const props = defineProps({
name: 'Dropdown',
components: { Collapsible },
directives: {},
props: {
dropdownClass: { dropdownClass: {
type: String, type: String,
default: 'origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 z-20' default: 'origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 z-20'
} }
}, })
setup () {
const isOpen = ref(false)
const open = () => { const isOpen = ref(false)
const dropdown = ref(null)
const open = (event) => {
isOpen.value = true isOpen.value = true
} }
const close = () => { const close = (event) => {
console.log('closing')
isOpen.value = false isOpen.value = false
} }
const toggle = () => { const toggle = (event) => {
isOpen.value = !isOpen.value isOpen.value = !isOpen.value
} }
return { const onClickAway = (event) => {
isOpen, // Check that event target isn't children of dropdown
open, if (dropdown.value && !dropdown.value.contains(event.target)) {
close, close(event)
toggle
}
} }
} }
</script> </script>

View File

@ -2,9 +2,7 @@
<NuxtLink v-if="href" :class="btnClasses" :href="href" :target="target"> <NuxtLink v-if="href" :class="btnClasses" :href="href" :target="target">
<slot /> <slot />
</NuxtLink> </NuxtLink>
<button v-else-if="!to" :type="nativeType" :disabled="loading?true:null" :class="btnClasses" <button v-else-if="!to" :type="nativeType" :disabled="loading?true:null" :class="btnClasses">
@click="onClick($event)"
>
<template v-if="!loading"> <template v-if="!loading">
<span class="no-underline mx-auto"> <span class="no-underline mx-auto">
<slot /> <slot />
@ -175,11 +173,5 @@ export default {
} }
} }
}, },
methods: {
onClick (event) {
this.$emit('click', event)
}
}
} }
</script> </script>

View File

@ -1,11 +1,9 @@
<template> <template>
<transition @leave="(el,done)=>motions.collapsible.leave(done)"> <transition @leave="onLeave">
<div <div
ref="collapsible" ref="collapsible"
v-if="modelValue" v-if="modelValue"
v-motion="'collapsible'" v-on-click-outside.bubble="onClickAway"
:variants="variants"
v-on-click-outside.bubble="close"
> >
<slot/> <slot/>
</div> </div>
@ -17,27 +15,38 @@ import {vOnClickOutside} from '@vueuse/components'
const props = defineProps({ const props = defineProps({
modelValue: {type: Boolean}, modelValue: {type: Boolean},
closeOnClickAway: {type: Boolean, default: true},
maxHeight: {type: Number, default: 200}, maxHeight: {type: Number, default: 200},
}) })
const emits = defineEmits(['update:modelValue']) const emits = defineEmits(['click-away'])
const motions = useMotions() const motion = ref(null)
const variants = ref({ const collapsible = ref(null)
enter: { const variants = {
opacity: 1,
y: 0,
transition: {duration: 150, ease: 'easeOut'}
},
initial: { initial: {
opacity: 0, opacity: 0,
y: -10, y: -10,
transition: {duration: 75, ease: 'easeIn'} transition: {duration: 75, ease: 'easeIn'}
}, },
}) enter: {
const close = () => { opacity: 1,
if (props.closeOnClickAway) { y: 0,
emits('update:modelValue', false) transition: {duration: 150, ease: 'easeOut'}
} }
} }
watch(() => props.modelValue, (newValue) => {
if (newValue) {
nextTick(() => {
motion.value = useMotion(collapsible.value, variants)
})
}
})
const onLeave = (el, done) => {
motion.value.leave(done)
}
const onClickAway = (event) => {
emits('click-away', event)
}
</script> </script>

View File

@ -3,9 +3,9 @@
<div v-if="loadingDuplicate || loadingDelete" class="pr-4 pt-2"> <div v-if="loadingDuplicate || loadingDelete" class="pr-4 pt-2">
<Loader class="h-6 w-6 mx-auto" /> <Loader class="h-6 w-6 mx-auto" />
</div> </div>
<dropdown v-else class="inline" dusk="nav-dropdown"> <dropdown v-else class="inline">
<template #trigger="{toggle}"> <template #trigger="{toggle}">
<v-button color="white" class="mr-2" @click.stop="toggle"> <v-button color="white" class="mr-2" @click="toggle">
<svg class="w-4 h-4 inline -mt-1" viewBox="0 0 16 4" fill="none" <svg class="w-4 h-4 inline -mt-1" viewBox="0 0 16 4" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
@ -42,7 +42,7 @@
View form View form
</a> </a>
<router-link v-if="isMainPage" v-track.edit_form_click="{form_id:form.id, form_slug:form.slug}" <router-link v-if="isMainPage" v-track.edit_form_click="{form_id:form.id, form_slug:form.slug}"
:to="{name:'forms.edit', params: {slug: form.slug}}" :to="{name:'forms-edit', params: {slug: form.slug}}"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center" class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
> >
<svg class="w-4 h-4 mr-2" width="18" height="17" viewBox="0 0 18 17" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="w-4 h-4 mr-2" width="18" height="17" viewBox="0 0 18 17" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -141,8 +141,6 @@
<script> <script>
import { computed } from 'vue' import { computed } from 'vue'
import axios from 'axios' import axios from 'axios'
import { useAuthStore } from '../../../../stores/auth'
import { useFormsStore } from '../../../../stores/forms'
import Dropdown from '~/components/global/Dropdown.vue' import Dropdown from '~/components/global/Dropdown.vue'
import FormTemplateModal from '../../../open/forms/components/templates/FormTemplateModal.vue' import FormTemplateModal from '../../../open/forms/components/templates/FormTemplateModal.vue'

View File

@ -263,7 +263,7 @@ export default {
this.$router.push({ name: 'home' }) this.$router.push({ name: 'home' })
}, },
openEdit () { openEdit () {
this.$router.push({ name: 'forms.edit', params: { slug: this.form.slug } }) this.$router.push({ name: 'forms-edit', params: { slug: this.form.slug } })
} }
} }
} }

View File

@ -170,8 +170,6 @@ const isFilteringForms = computed(() => {
const allTags = computed(() => { const allTags = computed(() => {
let tags = [] let tags = []
forms.value.forEach((form) => { forms.value.forEach((form) => {
console.log(form.tags)
// TODO: check this works
if (form.tags && form.tags.length) { if (form.tags && form.tags.length) {
tags = tags.concat(form.tags.split(',')) tags = tags.concat(form.tags.split(','))
} }

View File

@ -4,8 +4,8 @@
<loader class="h-6 w-6 mx-auto" /> <loader class="h-6 w-6 mx-auto" />
</div> </div>
<dropdown v-else class="inline" dusk="nav-dropdown"> <dropdown v-else class="inline" dusk="nav-dropdown">
<template #trigger="{toggle}"> <template #trigger="actions">
<v-button color="white" class="mr-2" @click.stop="toggle"> <v-button color="white" class="mr-2" @click.native="onClick(actions)">
<svg class="w-4 h-4 inline -mt-1" viewBox="0 0 16 4" fill="none" <svg class="w-4 h-4 inline -mt-1" viewBox="0 0 16 4" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
@ -147,8 +147,8 @@
</template> </template>
<script> <script>
import { computed } from 'vue'
import axios from 'axios' import axios from 'axios'
import { computed } from 'vue'
import { useAuthStore } from '../../../../stores/auth' import { useAuthStore } from '../../../../stores/auth'
import { useFormsStore } from '../../../../stores/forms' import { useFormsStore } from '../../../../stores/forms'
import Dropdown from '../../../common/Dropdown.vue' import Dropdown from '../../../common/Dropdown.vue'
@ -184,6 +184,9 @@ export default {
}, },
methods: { methods: {
onClick (actions) {
console.log('click', actions)
},
copyLink () { copyLink () {
const el = document.createElement('textarea') const el = document.createElement('textarea')
el.value = this.form.share_url el.value = this.form.share_url