Files
astra-frontend/src/components/base/BaseModal.vue
2023-02-22 15:34:46 +03:00

161 lines
4.3 KiB
Vue

<template lang="pug">
q-dialog(
v-model="value"
@show="onShow",
@hide="onHide",
ref="dialog"
)
.base-content(:class="{'draggable': draggable}", ref="contentRef", :style="{...contentStyles, height}")
q-resize-observer(@resize="onResize")
.base-header(draggable, :class="{'cursor-move': draggable}", ref="headerRef")
.header-title.text {{ title }}
.icon-cancel.text-sm(@click="value = false", v-if="!showCloseIcon")
slot
</template>
<script>
import { v_model } from "@/shared/mixins/v-model";
export default {
name: "BaseModal",
mixins: [v_model],
emits: ["show", "hide"],
props: {
title: String,
showCloseIcon: Boolean,
draggable: Boolean,
hideOverlay: Boolean,
height: {
type: String,
},
},
data() {
return {
contentStyles: {},
};
},
methods: {
onShow() {
if (this.draggable) {
this.$refs.headerRef.addEventListener("mousedown", this.onGrab);
}
this.$emit("show");
},
onHide() {
if (this.draggable) {
document.removeEventListener("mousemove", this.onDrag);
document.removeEventListener("mouseup", this.onLetGo);
}
this.$emit("hide");
},
onDrag(e) {
const target = this.$refs.contentRef;
const originalStyles = window.getComputedStyle(target);
const { x, width, y, height } = target.getBoundingClientRect();
if (
x + e.movementX > 10 &&
x + e.movementX + width + 10 <= window.innerWidth
)
this.contentStyles.left =
parseInt(originalStyles.left) + e.movementX + "px";
if (
y + e.movementY > 10 &&
y + e.movementY + height + 10 <= window.innerHeight
)
this.contentStyles.top =
parseInt(originalStyles.top) + e.movementY + "px";
this.contentStyles.bottom = "unset";
this.contentStyles.right = "unset";
},
onLetGo() {
document.removeEventListener("mousemove", this.onDrag);
document.removeEventListener("mouseup", this.onLetGo);
},
onGrab() {
document.addEventListener("mousemove", this.onDrag);
document.addEventListener("mouseup", this.onLetGo);
},
onResize() {
const target = this.$refs.contentRef;
const originalStyles = window.getComputedStyle(target);
const { x, width, y, height } = target.getBoundingClientRect();
if (x < 10) {
const delta = 10 - x;
this.contentStyles.left = parseInt(originalStyles.left) + delta + "px";
}
if (y < 10) {
const delta = 10 - y;
this.contentStyles.top = parseInt(originalStyles.top) + delta + "px";
}
if (x + width + 10 > window.innerWidth) {
const delta = window.innerWidth - (x + width + 10);
this.contentStyles.left = parseInt(originalStyles.left) + delta + "px";
}
if (y + height + 10 > window.innerHeight) {
const delta = window.innerHeight - (y + height + 10);
this.contentStyles.top = parseInt(originalStyles.top) + delta + "px";
}
},
},
updated() {
const backdropEl = this.$refs.dialog?.contentEl?.previousSibling;
if (!backdropEl) return;
if (!this.hideOverlay) {
backdropEl.style.background = "rgba(37, 40, 80, 0.2)";
backdropEl.style.backdropFilter = "blur(4px)";
} else backdropEl.style.background = "rgba(0,0,0,0)";
},
watch: {
value(val) {
if (val || !this.draggable) return;
this.contentStyles = {};
},
},
};
</script>
<style lang="sass" scoped>
.base-overlay
z-index: 10000
position: absolute
left: 0
top: 0
display: flex
justify-content: center
align-items: center
.base-content
width: auto
padding: 32px 40px
background-color: var(--default-white)
box-shadow: 4px 4px 8px rgba(9, 10, 21, 0.1), -4px -4px 8px rgba(9, 10, 21, 0.1)
border-radius: 4px
&.draggable
position: fixed
bottom: 10px
right: 10px
.header-title
font-weight: 700
font-size: 20px
line-height: 23px
color: var(--font-dark-blue-color)
user-select: none
.base-header
display: flex
justify-content: space-between
gap: 16px
.icon-cancel
margin-top: -11px
margin-right: -11px
cursor: pointer
color: var(--font-grey-color)
</style>
<style lang="sass">
@media (min-width: 600px)
.q-dialog__inner--minimized > div
max-width: 100vh !important
</style>