169 lines
4.5 KiB
Vue
169 lines
4.5 KiB
Vue
<template lang="pug">
|
|
q-dialog(
|
|
v-model="value"
|
|
@show="onShow",
|
|
@hide="onHide",
|
|
ref="dialog"
|
|
)
|
|
.base-content(
|
|
:class="{'draggable': draggable, 'base-content-default': !defaultPadding}",
|
|
ref="contentRef",
|
|
:style="{...contentStyles, height}"
|
|
)
|
|
q-resize-observer(@resize="onResize")
|
|
.base-header(v-if="!hideHeader" 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,
|
|
defaultPadding: Boolean,
|
|
hideHeader: 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-default
|
|
padding: 32px 40px
|
|
|
|
.base-content
|
|
width: auto
|
|
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>
|