Image.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. <template>
  2. <main>
  3. <div class="image-wrapper" :style="{width: width + 'px'}">
  4. <v-img
  5. :src="imageSrc"
  6. :lazy-src="defaultImagePath"
  7. :height="height"
  8. :width="width"
  9. aspect-ratio="1"
  10. >
  11. <template #placeholder>
  12. <v-row
  13. class="fill-height ma-0"
  14. align="center"
  15. justify="center"
  16. v-if="pending"
  17. >
  18. <v-progress-circular
  19. :indeterminate="true"
  20. color="grey lighten-1"
  21. />
  22. </v-row>
  23. </template>
  24. </v-img>
  25. <div>
  26. <div v-if="upload" class="click-action hover" @click="openUpload=true"><v-icon>mdi-upload</v-icon></div>
  27. <UiInputImage
  28. v-if="openUpload"
  29. @close="openUpload=false"
  30. :existingImageId="id"
  31. :field="field"
  32. :ownerId="ownerId"
  33. @update="$emit('update', $event, field); openUpload=false"
  34. @reload="onReload"
  35. @reset="reset"
  36. ></UiInputImage>
  37. </div>
  38. </div>
  39. </main>
  40. </template>
  41. <script setup lang="ts">
  42. import {ref, Ref} from "@vue/reactivity";
  43. import {useContext} from "unctx";
  44. import {useNuxtApp} from "#app";
  45. import {useImageFetch} from "~/composables/data/useImageFetch";
  46. import {onUnmounted, watch, WatchStopHandle} from "@vue/runtime-core";
  47. import {useImageManager} from "~/composables/data/useImageManager";
  48. const props = defineProps({
  49. id: {
  50. type: Number,
  51. required: true,
  52. default: null
  53. },
  54. field: {
  55. type: String,
  56. required: false
  57. },
  58. defaultImage: {
  59. type: String,
  60. required: false
  61. },
  62. height: {
  63. type: Number,
  64. required: false
  65. },
  66. width: {
  67. type: Number,
  68. required: false
  69. },
  70. upload: {
  71. type: Boolean,
  72. required: false,
  73. default: false
  74. },
  75. ownerId:{
  76. type: Number,
  77. required: false
  78. }
  79. })
  80. const { imageManager } = useImageManager()
  81. const { fetch } = useImageFetch()
  82. const defaultImagePath = props.defaultImage ?? imageManager.defaultImage
  83. const openUpload: Ref<Boolean> = ref(false)
  84. const imageSrc: Ref<string | null> = ref(null)
  85. let pending = ref(true)
  86. const fetchImage = async () => {
  87. pending.value = true
  88. imageSrc.value = await imageManager.get(props.id ?? null, defaultImagePath, props.height, props.width)
  89. pending.value = false
  90. }
  91. onMounted(
  92. () => {
  93. fetchImage()
  94. }
  95. )
  96. const unwatch: WatchStopHandle = watch(() => props.id, async (newValue, oldValue) => {
  97. await fetchImage()
  98. })
  99. const onReload = async () => {
  100. await fetchImage()
  101. openUpload.value = false
  102. }
  103. /**
  104. * Quand on souhaite faire un reset de l'image
  105. */
  106. const reset = () => {
  107. imageSrc.value = defaultImagePath
  108. openUpload.value = false
  109. }
  110. /**
  111. * Lorsqu'on démonte le component on supprime le watcher
  112. */
  113. onUnmounted(() => {
  114. unwatch()
  115. })
  116. </script>
  117. <style lang="scss">
  118. div.image-wrapper {
  119. display: block;
  120. position: relative;
  121. img{
  122. max-width: 100%;
  123. }
  124. .click-action{
  125. position: absolute;
  126. top:0;
  127. left:0;
  128. width: 100%;
  129. height: 100%;
  130. background: transparent;
  131. opacity: 0;
  132. transition: all .2s;
  133. &:hover{
  134. opacity: 1;
  135. background:rgba(0,0,0,0.3);
  136. cursor: pointer;
  137. }
  138. i{
  139. color: #fff;
  140. position: absolute;
  141. top: 50%;
  142. left: 50%;
  143. transform: translate(-50% , -50%);
  144. font-size: 50px;
  145. z-index: 1;
  146. opacity: 1;
  147. &:hover{
  148. color: rgba(#3fb37f, 0.7);
  149. }
  150. }
  151. }
  152. }
  153. </style>