Browse Source

feat(change-image-dialog): adiciona dialog ao clicar na imagem

ebagabee 3 tuần trước cách đây
mục cha
commit
0a2f4a01c5

+ 16 - 26
src/components/shared/AvatarImageComponent.vue

@@ -9,7 +9,7 @@
     <div
       v-if="!imageUrl"
       class="full-width full-height flex flex-center column gap-xs no-image-state"
-      @click="triggerFilePicker"
+      @click="openChangeDialog"
     >
       <q-icon name="add_photo_alternate" size="32px" color="grey-5" />
       <span class="text-grey-6" style="font-size: 12px">adicione uma imagem</span>
@@ -26,7 +26,7 @@
           icon="edit"
           color="grey-8"
           text-color="white"
-          @click.stop="triggerFilePicker"
+          @click.stop="openChangeDialog"
         >
           <q-tooltip>Trocar imagem</q-tooltip>
         </q-btn>
@@ -44,43 +44,29 @@
       </div>
     </template>
 
-    <q-file
-      ref="filePickerRef"
-      v-model="fileModel"
-      accept="image/*"
-      style="display: none"
-      @update:model-value="onFileSelected"
-    />
   </div>
 </template>
 
 <script setup>
 import { ref } from "vue";
+import { useQuasar } from "quasar";
+import ChangeImageDialog from "src/components/shared/ChangeImageDialog.vue";
 
 const emit = defineEmits(["update:file"]);
 
-const filePickerRef = ref(null);
-const fileModel = ref(null);
+const $q = useQuasar();
 const imageUrl = ref(null);
 const isDragOver = ref(false);
 
-function triggerFilePicker() {
-  filePickerRef.value.pickFiles();
-}
-
-function onFileSelected(file) {
-  if (!file) return;
-  const reader = new FileReader();
-  reader.onload = (e) => {
-    imageUrl.value = e.target.result;
-  };
-  reader.readAsDataURL(file);
-  emit("update:file", file);
+function openChangeDialog() {
+  $q.dialog({ component: ChangeImageDialog }).onOk(({ file, previewUrl }) => {
+    imageUrl.value = previewUrl;
+    emit("update:file", file);
+  });
 }
 
 function removeImage() {
   imageUrl.value = null;
-  fileModel.value = null;
   emit("update:file", null);
 }
 
@@ -88,8 +74,12 @@ function onDrop(event) {
   isDragOver.value = false;
   const file = event.dataTransfer.files[0];
   if (file && file.type.startsWith("image/")) {
-    fileModel.value = file;
-    onFileSelected(file);
+    const reader = new FileReader();
+    reader.onload = (e) => {
+      imageUrl.value = e.target.result;
+    };
+    reader.readAsDataURL(file);
+    emit("update:file", file);
   }
 }
 </script>

+ 81 - 0
src/components/shared/ChangeImageDialog.vue

@@ -0,0 +1,81 @@
+<template>
+  <q-dialog ref="dialogRef" @hide="onDialogHide">
+    <q-card class="q-dialog-plugin overflow-hidden" style="min-width: 400px">
+      <DefaultDialogHeader :title="() => 'Trocar Imagem'" @close="onDialogCancel" />
+
+      <q-card-section class="q-pt-none q-pb-sm">
+        <div class="text-caption text-grey-6 q-mb-xs">Personalizar</div>
+        <q-file
+          v-model="selectedFile"
+          accept="image/*"
+          outlined
+          dense
+          placeholder="Buscar no Desktop"
+          @update:model-value="onFileSelected"
+        >
+          <template #append>
+            <q-icon name="search" />
+          </template>
+        </q-file>
+      </q-card-section>
+
+      <q-card-section class="q-pt-none">
+        <div class="text-caption text-grey-6 q-mb-xs">Pré - Visualização</div>
+        <div class="preview-area flex flex-center">
+          <img v-if="previewUrl" :src="previewUrl" class="preview-image" />
+        </div>
+      </q-card-section>
+
+      <q-card-actions align="right">
+        <q-btn outline color="primary" label="Cancelar" @click="onDialogCancel" />
+        <q-btn color="primary" label="Salvar" :disable="!selectedFile" @click="onSave" />
+      </q-card-actions>
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { useDialogPluginComponent } from "quasar";
+import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
+
+defineEmits([...useDialogPluginComponent.emits]);
+
+const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent();
+
+const selectedFile = ref(null);
+const previewUrl = ref(null);
+
+function onFileSelected(file) {
+  if (!file) {
+    previewUrl.value = null;
+    return;
+  }
+  const reader = new FileReader();
+  reader.onload = (e) => {
+    previewUrl.value = e.target.result;
+  };
+  reader.readAsDataURL(file);
+}
+
+function onSave() {
+  onDialogOK({ file: selectedFile.value, previewUrl: previewUrl.value });
+}
+</script>
+
+<style scoped>
+.preview-area {
+  width: 100%;
+  height: 200px;
+  border: 1px solid #e0e0e0;
+  border-radius: 4px;
+  background-color: #fafafa;
+  overflow: hidden;
+}
+
+.preview-image {
+  max-width: 100%;
+  max-height: 100%;
+  object-fit: contain;
+}
+</style>