Image.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <template>
  2. <main>
  3. <div class="image-wrapper" :style="{width: width + 'px'}">
  4. <v-img
  5. :src="imgSrcReload ? imgSrcReload : image"
  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-progress-circular>
  23. </v-row>
  24. </template>
  25. </v-img>
  26. <div>
  27. <div v-if="upload" class="click-action hover" @click="openUpload=true"><v-icon>mdi-upload</v-icon></div>
  28. <UiInputImage
  29. v-if="openUpload"
  30. @close="openUpload=false"
  31. :existingImageId="id"
  32. :field="field"
  33. :ownerId="ownerId"
  34. @update="$emit('update', $event, field); openUpload=false"
  35. @reload="onReload"
  36. @reset="reset"
  37. ></UiInputImage>
  38. </div>
  39. </div>
  40. </main>
  41. </template>
  42. <script setup lang="ts">
  43. import {ref, Ref} from "@vue/reactivity";
  44. import {useContext} from "unctx";
  45. import {useNuxtApp} from "#app";
  46. import {useImageFetch} from "~/composables/data/useImageFetch";
  47. import {onUnmounted, watch, WatchStopHandle} from "@vue/runtime-core";
  48. const props = defineProps({
  49. id: {
  50. type: Number,
  51. required: false
  52. },
  53. field: {
  54. type: String,
  55. required: false
  56. },
  57. defaultImage: {
  58. type: String,
  59. required: false,
  60. default: 'picture.jpeg'
  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. // fetchOnServer: false, // TODO: je ne sais pas encore par quoi remplacer ça...
  81. if (!props.id) {
  82. throw new Error("Image's id is missing")
  83. }
  84. const defaultImagePath = `/images/default/${props.defaultImage}`
  85. const openUpload: Ref<Boolean> = ref(false)
  86. const imgSrcReload: Ref<any> = ref(null)
  87. const { $config } = useNuxtApp()
  88. const { fetch } = useImageFetch()
  89. const { data: image, pending } = fetch(props.id, props.defaultImage, props.height, props.width)
  90. const unwatch: WatchStopHandle = watch(() => props.id, async (newValue, oldValue) => {
  91. imgSrcReload.value = await fetch(newValue as number, props.defaultImage, props.height, props.width)
  92. })
  93. const onReload = () => {
  94. fetch()
  95. openUpload.value = false
  96. }
  97. /**
  98. * Quand on souhaite faire un reset de l'image
  99. */
  100. const reset = () => {
  101. imgSrcReload.value = null
  102. image.value = require(defaultImagePath)
  103. openUpload.value = false
  104. }
  105. /**
  106. * Lorsqu'on démonte le component on supprime le watcher
  107. */
  108. onUnmounted(() => {
  109. unwatch()
  110. })
  111. </script>
  112. <style lang="scss">
  113. div.image-wrapper {
  114. display: block;
  115. position: relative;
  116. img{
  117. max-width: 100%;
  118. }
  119. .click-action{
  120. position: absolute;
  121. top:0;
  122. left:0;
  123. width: 100%;
  124. height: 100%;
  125. background: transparent;
  126. opacity: 0;
  127. transition: all .2s;
  128. &:hover{
  129. opacity: 1;
  130. background:rgba(0,0,0,0.3);
  131. cursor: pointer;
  132. }
  133. i{
  134. color: #fff;
  135. position: absolute;
  136. top: 50%;
  137. left: 50%;
  138. transform: translate(-50% , -50%);
  139. font-size: 50px;
  140. z-index: 1;
  141. opacity: 1;
  142. &:hover{
  143. color: rgba(#3fb37f, 0.7);
  144. }
  145. }
  146. }
  147. }
  148. </style>