forked from vikunja/frontend
feat: create new popup component to handle popups generally
This commit is contained in:
parent
9250f4e76b
commit
86efb07f09
|
@ -6,39 +6,42 @@
|
||||||
>
|
>
|
||||||
{{ $t('filters.clear') }}
|
{{ $t('filters.clear') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<filters
|
<popup>
|
||||||
:class="{'is-open': visibleInternal}"
|
<template #trigger="{toggle}">
|
||||||
class="filter-popup"
|
<x-button
|
||||||
v-model="value"
|
@click.prevent.stop="toggle()"
|
||||||
ref="filters"
|
type="secondary"
|
||||||
/>
|
icon="filter"
|
||||||
|
>
|
||||||
|
{{ $t('filters.title') }}
|
||||||
|
</x-button>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<filters
|
||||||
|
v-model="value"
|
||||||
|
ref="filters"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</popup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
|
||||||
import Filters from '../../../components/list/partials/filters'
|
import Filters from '../../../components/list/partials/filters'
|
||||||
import {getDefaultParams} from '../../tasks/mixins/taskList'
|
import {getDefaultParams} from '../../tasks/mixins/taskList'
|
||||||
|
import Popup from '../../misc/popup'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'filter-popup',
|
name: 'filter-popup',
|
||||||
components: {
|
components: {
|
||||||
|
Popup,
|
||||||
Filters,
|
Filters,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
modelValue: {
|
modelValue: {
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
visibleInternal: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
value: {
|
value: {
|
||||||
get() {
|
get() {
|
||||||
|
@ -65,12 +68,6 @@ export default {
|
||||||
return JSON.stringify(filterParams) !== JSON.stringify(def)
|
return JSON.stringify(filterParams) !== JSON.stringify(def)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
document.addEventListener('click', this.hidePopup)
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
document.removeEventListener('click', this.hidePopup)
|
|
||||||
},
|
|
||||||
watch: {
|
watch: {
|
||||||
modelValue: {
|
modelValue: {
|
||||||
handler(value) {
|
handler(value) {
|
||||||
|
@ -78,43 +75,11 @@ export default {
|
||||||
},
|
},
|
||||||
immediate: true,
|
immediate: true,
|
||||||
},
|
},
|
||||||
visible() {
|
|
||||||
this.visibleInternal = !this.visibleInternal
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hidePopup(e) {
|
|
||||||
if (!this.visibleInternal) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
closeWhenClickedOutside(e, this.$refs.filters.$el, () => {
|
|
||||||
this.visibleInternal = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
clearFilters() {
|
clearFilters() {
|
||||||
this.value = {...getDefaultParams()}
|
this.value = {...getDefaultParams()}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.filter-popup {
|
|
||||||
transition: opacity $transition;
|
|
||||||
opacity: 0;
|
|
||||||
height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 2rem;
|
|
||||||
margin: 0 !important;
|
|
||||||
border-width: 0 !important;
|
|
||||||
|
|
||||||
&.is-open {
|
|
||||||
opacity: 1;
|
|
||||||
height: auto;
|
|
||||||
margin: 1rem 0 !important;
|
|
||||||
border-width: 1px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
63
src/components/misc/popup.vue
Normal file
63
src/components/misc/popup.vue
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<template>
|
||||||
|
<slot name="trigger" :isOpen="open" :toggle="toggle"></slot>
|
||||||
|
<div class="popup" :class="{'is-open': open}">
|
||||||
|
<slot ref="popupContent"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
||||||
|
import {onBeforeUnmount, onMounted, ref} from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const open = ref(false)
|
||||||
|
const popupContent = ref(null)
|
||||||
|
|
||||||
|
const toggle = () => {
|
||||||
|
open.value = !open.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const hidePopup = e => {
|
||||||
|
if (!open.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
closeWhenClickedOutside(e, popupContent.$el, () => {
|
||||||
|
open.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('click', hidePopup)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
document.removeEventListener('click', hidePopup)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
open,
|
||||||
|
toggle,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.popup {
|
||||||
|
transition: opacity $transition;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
margin: 0 !important;
|
||||||
|
|
||||||
|
&.is-open {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
margin: 1rem 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,16 +1,14 @@
|
||||||
import TaskCollectionService from '@/services/taskCollection'
|
import TaskCollectionService from '@/services/taskCollection'
|
||||||
|
|
||||||
// FIXME: merge with DEFAULT_PARAMS in filters.vue
|
// FIXME: merge with DEFAULT_PARAMS in filters.vue
|
||||||
const DEFAULT_PARAMS = {
|
export const getDefaultParams = () => ({
|
||||||
sort_by: ['position', 'id'],
|
sort_by: ['position', 'id'],
|
||||||
order_by: ['asc', 'desc'],
|
order_by: ['asc', 'desc'],
|
||||||
filter_by: ['done'],
|
filter_by: ['done'],
|
||||||
filter_value: ['false'],
|
filter_value: ['false'],
|
||||||
filter_comparator: ['equals'],
|
filter_comparator: ['equals'],
|
||||||
filter_concat: 'and',
|
filter_concat: 'and',
|
||||||
}
|
})
|
||||||
|
|
||||||
export const getDefaultParams = () => ({...DEFAULT_PARAMS})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This mixin provides a base set of methods and properties to get tasks on a list.
|
* This mixin provides a base set of methods and properties to get tasks on a list.
|
||||||
|
|
|
@ -2,16 +2,9 @@
|
||||||
<div class="kanban-view">
|
<div class="kanban-view">
|
||||||
<div class="filter-container" v-if="isSavedFilter">
|
<div class="filter-container" v-if="isSavedFilter">
|
||||||
<div class="items">
|
<div class="items">
|
||||||
<x-button
|
|
||||||
@click.prevent.stop="toggleFilterPopup"
|
|
||||||
icon="filter"
|
|
||||||
type="secondary"
|
|
||||||
>
|
|
||||||
{{ $t('filters.title') }}
|
|
||||||
</x-button>
|
|
||||||
<filter-popup
|
<filter-popup
|
||||||
:visible="showFilters"
|
|
||||||
v-model="params"
|
v-model="params"
|
||||||
|
@update:modelValue="loadBuckets"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -300,7 +293,6 @@ export default {
|
||||||
filter_comparator: [],
|
filter_comparator: [],
|
||||||
filter_concat: 'and',
|
filter_concat: 'and',
|
||||||
},
|
},
|
||||||
showFilters: false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -359,10 +351,6 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
toggleFilterPopup() {
|
|
||||||
this.showFilters = !this.showFilters
|
|
||||||
},
|
|
||||||
|
|
||||||
loadBuckets() {
|
loadBuckets() {
|
||||||
// Prevent trying to load buckets if the task popup view is active
|
// Prevent trying to load buckets if the task popup view is active
|
||||||
if (this.$route.name !== 'list.kanban') {
|
if (this.$route.name !== 'list.kanban') {
|
||||||
|
|
|
@ -41,15 +41,7 @@
|
||||||
v-if="!showTaskSearch"
|
v-if="!showTaskSearch"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<x-button
|
|
||||||
@click.prevent.stop="showTaskFilter = !showTaskFilter"
|
|
||||||
type="secondary"
|
|
||||||
icon="filter"
|
|
||||||
>
|
|
||||||
{{ $t('filters.title') }}
|
|
||||||
</x-button>
|
|
||||||
<filter-popup
|
<filter-popup
|
||||||
:visible="showTaskFilter"
|
|
||||||
v-model="params"
|
v-model="params"
|
||||||
@update:modelValue="loadTasks()"
|
@update:modelValue="loadTasks()"
|
||||||
/>
|
/>
|
||||||
|
@ -154,6 +146,7 @@ import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
||||||
import {HAS_TASKS} from '@/store/mutation-types'
|
import {HAS_TASKS} from '@/store/mutation-types'
|
||||||
import Nothing from '@/components/misc/nothing.vue'
|
import Nothing from '@/components/misc/nothing.vue'
|
||||||
import Pagination from '@/components/misc/pagination.vue'
|
import Pagination from '@/components/misc/pagination.vue'
|
||||||
|
import Popup from '@/components/misc/popup'
|
||||||
|
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
||||||
|
@ -197,6 +190,7 @@ export default {
|
||||||
taskList,
|
taskList,
|
||||||
],
|
],
|
||||||
components: {
|
components: {
|
||||||
|
Popup,
|
||||||
Nothing,
|
Nothing,
|
||||||
FilterPopup,
|
FilterPopup,
|
||||||
SingleTaskInList,
|
SingleTaskInList,
|
||||||
|
|
|
@ -3,21 +3,13 @@
|
||||||
<div class="filter-container">
|
<div class="filter-container">
|
||||||
<div class="items">
|
<div class="items">
|
||||||
<x-button
|
<x-button
|
||||||
@click.prevent.stop="() => {showActiveColumnsFilter = !showActiveColumnsFilter; showTaskFilter = false}"
|
@click.prevent.stop="showActiveColumnsFilter = !showActiveColumnsFilter"
|
||||||
icon="th"
|
icon="th"
|
||||||
type="secondary"
|
type="secondary"
|
||||||
>
|
>
|
||||||
{{ $t('list.table.columns') }}
|
{{ $t('list.table.columns') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
|
||||||
@click.prevent.stop="() => {showTaskFilter = !showTaskFilter; showActiveColumnsFilter = false}"
|
|
||||||
icon="filter"
|
|
||||||
type="secondary"
|
|
||||||
>
|
|
||||||
{{ $t('filters.title') }}
|
|
||||||
</x-button>
|
|
||||||
<filter-popup
|
<filter-popup
|
||||||
:visible="showTaskFilter"
|
|
||||||
v-model="params"
|
v-model="params"
|
||||||
@update:modelValue="loadTasks()"
|
@update:modelValue="loadTasks()"
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user