From 2f7153fbfee2e3131eed68b390b37297ee1aff65 Mon Sep 17 00:00:00 2001
From: Dennis Postma <dennis@directonline.io>
Date: Mon, 10 Jun 2024 01:42:57 +0200
Subject: [PATCH] Added resizing logics to modal + option to disable this

---
 public/assets/icons/resize-icon.svg |  4 ++
 src/components/screens/Login.vue    |  1 +
 src/components/utilities/Modal.vue  | 84 +++++++++++++++++++++++++++--
 3 files changed, 86 insertions(+), 3 deletions(-)
 create mode 100644 public/assets/icons/resize-icon.svg

diff --git a/public/assets/icons/resize-icon.svg b/public/assets/icons/resize-icon.svg
new file mode 100644
index 0000000..abbecc7
--- /dev/null
+++ b/public/assets/icons/resize-icon.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21 15L15 21M21 8L8 21" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
\ No newline at end of file
diff --git a/src/components/screens/Login.vue b/src/components/screens/Login.vue
index 3f5cf59..8a4eed7 100644
--- a/src/components/screens/Login.vue
+++ b/src/components/screens/Login.vue
@@ -122,6 +122,7 @@ async function registerFunc() {
           flex-direction: column;
           background-color: rgba($white, 0.5);
           border-radius: 3px;
+          border: $light-gray 1px solid;
           min-width: 400px;
           margin: 0 auto;
 
diff --git a/src/components/utilities/Modal.vue b/src/components/utilities/Modal.vue
index 5e539f9..c1f80c1 100644
--- a/src/components/utilities/Modal.vue
+++ b/src/components/utilities/Modal.vue
@@ -1,6 +1,6 @@
 <template>
   <Teleport to="body">
-    <div class="modal-container" :style="{ top: y + 'px', left: x + 'px' }" v-if="isModalOpenRef">
+    <div class="modal-container" v-if="isModalOpenRef" :style="{ top: y + 'px', left: x + 'px', width: width + 'px', height: height + 'px' }">
       <div class="modal-header" @mousedown="startDrag">
         <slot name="modalHeader" />
         <div class="buttons">
@@ -10,6 +10,7 @@
       </div>
       <div class="modal-body">
         <slot name="modalBody" />
+        <img v-if="isResizable" src="/assets/icons/resize-icon.svg" alt="resize" class="resize" @mousedown="startResize" />
       </div>
       <div v-if="$slots.modalFooter" class="modal-footer">
         <slot name="modalFooter" />
@@ -29,6 +30,18 @@ const properties = defineProps({
   closable: {
     type: Boolean,
     default: true
+  },
+  isResizable: {
+    type: Boolean,
+    default: true
+  },
+  modalWidth: {
+    type: Number,
+    default: 500
+  },
+  modalHeight: {
+    type: Number,
+    default: 280
   }
 })
 
@@ -46,6 +59,35 @@ function close() {
   emit('modal:close')
 }
 
+// (re)size logics
+const width = ref(properties.modalWidth)
+const height = ref(properties.modalHeight)
+let minWidth = ref(200)
+let minHeight = ref(100)
+let isResizing = ref(false)
+
+let startWidth = 0
+let startHeight = 0
+
+const startResize = (event: MouseEvent) => {
+  isResizing.value = true
+  startWidth = width.value - event.clientX
+  startHeight = height.value - event.clientY
+  event.preventDefault()
+}
+
+const resizeModal = (event: MouseEvent) => {
+  if (!isResizing.value) return
+  let newWidth = startWidth + event.clientX
+  let newHeight = startHeight + event.clientY
+  width.value = newWidth > minWidth.value ? newWidth : minWidth.value
+  height.value = newHeight > minHeight.value ? newHeight : minHeight.value
+}
+
+const stopResize = () => {
+  isResizing.value = false
+}
+
 // make modal draggable
 let startX = 0
 let startY = 0
@@ -85,13 +127,41 @@ const stopDrag = () => {
 onMounted(() => {
   addEventListener('mousemove', drag)
   addEventListener('mouseup', stopDrag)
+  addEventListener('mousemove', resizeModal)
+  addEventListener('mouseup', stopResize)
+  addEventListener('resize', handleResize)
 })
 
 onUnmounted(() => {
   removeEventListener('mousemove', drag)
   removeEventListener('mouseup', stopDrag)
+  removeEventListener('mousemove', resizeModal)
+  removeEventListener('mouseup', stopResize)
+  removeEventListener('resize', handleResize)
 })
 
+
+// Make sure modal doesn't go off screen
+watch(
+  () => x.value, (value) => {
+    if (value < 0) { x.value = 0 } else if (value + width.value > window.innerWidth) { x.value = window.innerWidth - width.value }
+  }
+)
+watch(
+  () => y.value, (value) => {
+    if (value < 0) { y.value = 0 } else if (value + height.value > window.innerHeight) { y.value = window.innerHeight - height.value }
+  }
+)
+
+// also on window resize function
+function handleResize() {
+  if (x.value + width.value > window.innerWidth) {
+    x.value = window.innerWidth - width.value
+  }
+  if (y.value + height.value > window.innerHeight) {
+    y.value = window.innerHeight - height.value
+  }
+}
 </script>
 
 <style lang="scss">
@@ -102,8 +172,6 @@ onUnmounted(() => {
   top: 0;
   left: 0;
   max-width: 1000px;
-  min-width: 500px;
-  min-height: 280px;
   background-color: rgba($dark-gray, 0.8);
   border: 2px solid $dark-cyan;
   z-index: 999;
@@ -158,6 +226,16 @@ onUnmounted(() => {
     padding: 15px;
     flex-grow: 1;
 
+    .resize {
+      filter: invert(60%);
+      position: absolute;
+      bottom: 0;
+      right: 0;
+      width: 20px;
+      height: 20px;
+      cursor: nwse-resize;
+    }
+
     .submit {
       display: inline-block;
       button {