{"version":3,"file":"AvatarEditor-c520e3d6.cjs","sources":["../src/components/user/AvatarEditor.vue"],"sourcesContent":["<template>\n  <div class=\"flex flex-col space-y-2\">\n    <div class=\"flex\">\n      <div class=\"flex flex-col px-2 space-y-1\" :class=\"{ invisible: !activeImageUrl }\">\n        <FormButton\n          v-tippy=\"'Rotate left'\"\n          :icon-left=\"ArrowUturnLeftIcon\"\n          hide-text\n          color=\"outline\"\n          @click=\"rotateLeft\"\n        />\n        <FormButton\n          v-tippy=\"'Rotate right'\"\n          :icon-left=\"ArrowUturnRightIcon\"\n          hide-text\n          color=\"outline\"\n          @click=\"rotateRight\"\n        />\n        <FormButton\n          v-tippy=\"'Flip vertically'\"\n          :icon-left=\"ArrowUpOnSquareIcon\"\n          hide-text\n          color=\"outline\"\n          @click=\"flipVertical\"\n        />\n        <FormButton\n          v-tippy=\"'Flip horizontally'\"\n          :icon-left=\"ArrowLeftOnRectangleIcon\"\n          hide-text\n          color=\"outline\"\n          @click=\"flipHorizontal\"\n        />\n      </div>\n      <Cropper\n        v-if=\"activeImageUrl\"\n        ref=\"cropper\"\n        class=\"cropper\"\n        :src=\"activeImageUrl\"\n        :stencil-props=\"{\n          aspectRatio: 1 / 1\n        }\"\n        :canvas=\"canvasSize\"\n        :style=\"`width: ${canvasSize.width}px; height: ${canvasSize.height}px`\"\n      />\n      <FormFileUploadZone\n        ref=\"uploadZone\"\n        v-slot=\"{ isDraggingFiles, activatorOn }\"\n        class=\"cropper flex items-center justify-center\"\n        :class=\"{ hidden: activeImageUrl }\"\n        accept=\"image/*\"\n        :size-limit=\"5 * 1024 * 1024\"\n        @files-selected=\"onFilesSelected\"\n      >\n        <div\n          class=\"cursor-pointer text-center w-full h-full border-dashed border-2 rounded-md p-4 flex items-center justify-center text-sm text-foreground-2\"\n          :class=\"[getDashedBorderClasses(isDraggingFiles)]\"\n          v-on=\"activatorOn\"\n        >\n          Click here or drag and drop an image\n        </div>\n      </FormFileUploadZone>\n      <div class=\"flex flex-col px-2 space-y-1\" :class=\"{ invisible: !activeImageUrl }\">\n        <FormButton\n          v-tippy=\"'Replace image'\"\n          :icon-left=\"PhotoIcon\"\n          hide-text\n          @click=\"onReplace\"\n        />\n        <FormButton\n          v-tippy=\"'Remove'\"\n          :icon-left=\"XMarkIcon\"\n          hide-text\n          color=\"danger\"\n          @click=\"onRemove\"\n        />\n      </div>\n    </div>\n    <div class=\"flex mx-14 space-x-2\">\n      <div class=\"grow\" />\n      <FormButton color=\"outline\" @click=\"$emit('cancel')\">Close</FormButton>\n      <FormButton :disabled=\"disabled\" @click=\"onSave\">Save</FormButton>\n    </div>\n  </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n  ArrowUturnLeftIcon,\n  ArrowUturnRightIcon,\n  ArrowLeftOnRectangleIcon,\n  ArrowUpOnSquareIcon,\n  XMarkIcon,\n  PhotoIcon\n} from '@heroicons/vue/24/outline'\nimport type { Nullable } from '@speckle/shared'\nimport { onUnmounted, ref, watch, computed } from 'vue'\nimport { Cropper } from 'vue-advanced-cropper'\nimport 'vue-advanced-cropper/dist/style.css'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport FormFileUploadZone from '~~/src/components/form/file-upload/Zone.vue'\nimport type { UploadableFileItem } from '~~/src/composables/form/fileUpload'\nimport type { AvatarUser, UserAvatarSize } from '~~/src/composables/user/avatar'\nimport { directive as vTippy } from 'vue-tippy'\n\n/**\n * Always try to lazy load this, as it's quite heavy\n */\n\nconst emit = defineEmits<{\n  (e: 'cancel'): void\n  (e: 'save', val: Nullable<string>): void\n}>()\n\nconst props = defineProps<{\n  user: AvatarUser\n  disabled?: boolean\n  size?: UserAvatarSize\n}>()\n\nconst cropper = ref(\n  null as Nullable<{\n    flip: (x: number, y: number) => void\n    rotate: (angle: number) => void\n    getResult: () => { canvas: HTMLCanvasElement }\n  }>\n)\nconst uploadZone = ref(null as Nullable<{ triggerPicker: () => void }>)\nconst selectedUpload = ref(null as Nullable<UploadableFileItem>)\nconst activeImageUrl = ref(null as Nullable<string>)\n\nconst canvasSize = computed(() => {\n  switch (props.size) {\n    case 'xs':\n    case 'sm':\n    case 'lg':\n    case 'xl':\n      return { width: 64, height: 64 }\n    case 'xxl':\n    case '3xl':\n      return { width: 140, height: 140 }\n    case 'editable':\n      return { width: 240, height: 240 }\n    case 'base':\n    default:\n      return { width: 32, height: 32 }\n  }\n})\n\nconst setNewActiveUrl = (url: Nullable<string>) => {\n  if (activeImageUrl.value) {\n    URL.revokeObjectURL(activeImageUrl.value)\n  }\n\n  activeImageUrl.value = url\n}\n\nconst onFilesSelected = (params: { files: UploadableFileItem[] }) => {\n  const file = params.files[0]\n  if (!file) return\n  selectedUpload.value = file\n}\n\nconst getDashedBorderClasses = (isDraggingFiles: boolean) => {\n  if (isDraggingFiles) return 'border-primary'\n  if (selectedUpload.value?.error) return 'border-danger'\n\n  return 'border-outline-2'\n}\n\nconst rotateLeft = () => cropper.value?.rotate(-90)\nconst rotateRight = () => cropper.value?.rotate(90)\nconst flipHorizontal = () => cropper.value?.flip(1, 0)\nconst flipVertical = () => cropper.value?.flip(0, 1)\n\nconst onReplace = () => uploadZone.value?.triggerPicker()\nconst onRemove = () => {\n  selectedUpload.value = null\n  activeImageUrl.value = null\n}\nconst onSave = () => {\n  const newUrl = cropper.value?.getResult().canvas.toDataURL('image/jpeg', 0.85) || null\n  emit('save', newUrl)\n}\n\nonUnmounted(() => {\n  setNewActiveUrl(null)\n})\n\nwatch(\n  () => props.user.avatar,\n  (newAvatar) => {\n    activeImageUrl.value = newAvatar || null\n  },\n  { immediate: true }\n)\n\nwatch(\n  selectedUpload,\n  (newUpload) => {\n    activeImageUrl.value =\n      newUpload?.file && !newUpload.error ? URL.createObjectURL(newUpload.file) : null\n  },\n  { deep: true }\n)\n</script>\n"],"names":["emit","__emit","props","__props","cropper","ref","uploadZone","selectedUpload","activeImageUrl","canvasSize","computed","setNewActiveUrl","url","onFilesSelected","params","file","getDashedBorderClasses","isDraggingFiles","_a","rotateLeft","rotateRight","flipHorizontal","flipVertical","onReplace","onRemove","onSave","newUrl","onUnmounted","watch","newAvatar","newUpload","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_normalizeClass","_createVNode","FormButton","_unref","ArrowUturnLeftIcon","ArrowUturnRightIcon","ArrowUpOnSquareIcon","ArrowLeftOnRectangleIcon","_createBlock","Cropper","FormFileUploadZone","activatorOn","_mergeProps","_toHandlers","PhotoIcon","XMarkIcon","_hoisted_3","$emit","_cache","disabled"],"mappings":"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"}