From 2fa6ad5583a5cfb918e1e6e8d02d95461f5d7dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guczi=20=C3=81d=C3=A1m?= Date: Tue, 15 Feb 2022 23:33:19 +0100 Subject: [PATCH] Pin popover --- package.json | 2 +- src/components/BasePopover.vue | 99 +++++++++++++++++++++++------ src/components/popovers/Popover.vue | 7 +- 3 files changed, 87 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 838949e..fb3ec7c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scheduler", - "version": "0.1.11", + "version": "0.1.12", "private": true, "repository": { "type" : "git", diff --git a/src/components/BasePopover.vue b/src/components/BasePopover.vue index a474ba7..0d0f50e 100644 --- a/src/components/BasePopover.vue +++ b/src/components/BasePopover.vue @@ -17,6 +17,14 @@ export default defineComponent({ type: Object as () => { x: number, y: number }, default: () => ({ x: 0, y: 0 }) }, + position: { + type: Object as () => { x: number, y: number }, + default: () => ({ x: 0, y: 0 }) + }, + absolute: { + type: Boolean, + default: false + }, margin: { type: Number, default: 10 @@ -36,7 +44,6 @@ export default defineComponent({ const popover = ref() // Template ref to popover let updateDimensions = () => { - // console.log(popover) let rect = popover.value?.getBoundingClientRect(); popoverWidth.value = rect?.width ?? 0; popoverHeight.value = rect?.height ?? 0; @@ -48,25 +55,44 @@ export default defineComponent({ let popoverHeight = ref(100); let x = computed(() => { - let { offset: { x: offset }, margin } = props; - if (!targetStartRect.value || !targetEndRect.value) return offset - let { left } = targetStartRect.value - let { right } = targetEndRect.value - let x = left + (right - left - popoverWidth.value) / 2 + offset; - return _.clamp(x, margin, window.innerWidth - popoverWidth.value - margin) + let { offset: { x: offset }, margin, position, absolute } = props; + let maxLeft = window.innerWidth - popoverWidth.value - margin; + + let res = -1; + if (absolute) + res = position.x; + else { + if (!targetStartRect.value || !targetEndRect.value) return offset + let { left } = targetStartRect.value + let { right } = targetEndRect.value + res = left + (right - left - popoverWidth.value) / 2 + offset; + position.x = res; + } + + return _.clamp(res, margin, maxLeft); }) let y = computed(() => { - let { offset: { y: offset }, margin } = props; - if (!targetStartRect.value) return offset - let { bottom, top } = targetStartRect.value + let { offset: { y: offset }, margin, position, absolute } = props; + let maxTop = window.innerHeight - popoverHeight.value - margin; + + let res = -1; + if (absolute) + res = position.y; + else { + if (!targetStartRect.value) return offset + let { bottom, top } = targetStartRect.value + + // If the popover would cover the target move the popover above it + if (bottom > maxTop) + res = top - offset - popoverHeight.value; + else + res = bottom + offset; - // If the popover would cover the target move the popover above it - let maxTop = window.innerHeight - popoverHeight.value - margin - if (bottom > maxTop) - return _.clamp(top - offset - popoverHeight.value, margin, maxTop) + position.y = res; + } - return _.clamp(bottom + offset, margin, maxTop) + return _.clamp(res, margin, maxTop); }) let style = computed(() => { @@ -74,24 +100,60 @@ export default defineComponent({ left: x.value + "px", top: y.value + "px", visibility: props.value ? "visible" : "hidden", - opacity: props.value ? "1" : "0" + opacity: props.value ? "1" : "0", + cursor: props.absolute ? "grab" : "default", + transitionDuration: drag.dragging ? "0ms" : "300ms" } }) + let drag = { + offset: { + x: 0, + y: 0 + }, + dragging: false + } + + let dragStart = (e: MouseEvent) => { + drag.dragging = true; + let rect: DOMRect = popover.value?.getBoundingClientRect(); + drag.offset.x = e.x - rect.x + drag.offset.y = e.y - rect.y + } + + window.addEventListener("mousemove", (e) => { + let { position, absolute } = props; + if (!drag.dragging || !absolute ) return; + e.preventDefault() + position.x = e.pageX - drag.offset.x; + position.y = e.pageY - drag.offset.y; + }) + + window.addEventListener("mouseup", (e) => { + console.log("mouseup") + + drag.dragging = false; + }) + watch(() => props.targets, () => { updateRects() root.$nextTick(updateDimensions) }) return { - x, y, style, popoverWidth, popoverHeight, updateRects, popover + x, y, style, popoverWidth, popoverHeight, updateRects, popover, + dragStart } }, }) @@ -101,7 +163,6 @@ export default defineComponent({ position: fixed; z-index: 5; transition-property: left, top, visibility, opacity; - transition-duration: 300ms; transition-delay: 0ms, 0ms, 100ms, 100ms; } diff --git a/src/components/popovers/Popover.vue b/src/components/popovers/Popover.vue index 4005e7b..8f4e36b 100644 --- a/src/components/popovers/Popover.vue +++ b/src/components/popovers/Popover.vue @@ -34,7 +34,8 @@ export default Vue.extend({ shift: {start: 7, end: 19, duration: 12} as Shift, leave_buttons: [DayType.paid, DayType.freeday, DayType.nonworking_day, DayType.weekend, DayType.sick, DayType.holiday] as DayType[], accelerators: ["f", "s", "p", "h", "t", "ü", "Delete", "Enter", "Escape"], //Last three are used only in IgnoreKeys - last_action: "" + last_action: "", + pinned: false }; }, computed: { @@ -94,9 +95,13 @@ export default Vue.extend({ v-model="value" :targets="selection_elements" :offset="{x: 0, y: 12}" + :absolute="pinned" ref="base"> + + {{pinned ? "mdi-pin" : "mdi-pin-outline" }} + mdi-close