renusify 2.5.2 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/components/app/index.vue +74 -22
  2. package/components/app/toast/index.vue +76 -71
  3. package/components/app/toast/toast.vue +62 -44
  4. package/components/avatar/index.vue +207 -84
  5. package/components/button/buttonConfirm.vue +53 -26
  6. package/components/button/buttonGroup.js +0 -2
  7. package/components/button/buttonGroup.vue +310 -62
  8. package/components/button/index.vue +584 -100
  9. package/components/calendar/index.js +0 -2
  10. package/components/calendar/index.vue +326 -262
  11. package/components/calendar/month.vue +64 -55
  12. package/components/calendar/year.vue +30 -25
  13. package/components/card/index.vue +139 -59
  14. package/components/codeEditor/highlightCss.vue +38 -39
  15. package/components/codeEditor/highlightHtml.vue +64 -64
  16. package/components/codeEditor/highlightJs.vue +37 -38
  17. package/components/codeEditor/index.vue +129 -79
  18. package/components/codeEditor/run.vue +225 -39
  19. package/components/codeEditor/useCodeFormatter.js +150 -0
  20. package/components/confirm/index.vue +139 -80
  21. package/components/container/col.vue +5 -4
  22. package/components/container/divider.vue +28 -19
  23. package/components/container/index.vue +34 -15
  24. package/components/container/row.vue +26 -9
  25. package/components/container/spacer.vue +2 -4
  26. package/components/container/style.scss +3 -0
  27. package/components/content/index.vue +49 -32
  28. package/components/cropper/index.vue +401 -244
  29. package/components/float/index.vue +542 -415
  30. package/components/form/addressInput/index.vue +184 -109
  31. package/components/form/camInput/index.vue +370 -244
  32. package/components/form/checkInput/index.vue +138 -71
  33. package/components/form/checkboxInput/index.vue +93 -49
  34. package/components/form/colorInput/Alpha.vue +81 -83
  35. package/components/form/colorInput/Hue.vue +91 -68
  36. package/components/form/colorInput/Preview.vue +43 -47
  37. package/components/form/colorInput/Saturation.vue +101 -86
  38. package/components/form/colorInput/index.vue +71 -39
  39. package/components/form/colorInput/picker.vue +111 -106
  40. package/components/form/colorInput/useColor.js +153 -0
  41. package/components/form/dateInput/index.vue +691 -356
  42. package/components/form/dateInput/month.vue +63 -54
  43. package/components/form/dateInput/year.vue +35 -25
  44. package/components/form/fileInput/index.js +0 -1
  45. package/components/form/fileInput/index.vue +263 -106
  46. package/components/form/fileInput/single.vue +332 -168
  47. package/components/form/groupInput/index.vue +199 -101
  48. package/components/form/index.vue +189 -83
  49. package/components/form/input/index.vue +416 -377
  50. package/components/form/jsonInput/JsonView.vue +54 -56
  51. package/components/form/jsonInput/index.vue +247 -165
  52. package/components/form/maskInput/index.vue +252 -132
  53. package/components/form/numberInput/index.js +0 -1
  54. package/components/form/numberInput/index.vue +226 -117
  55. package/components/form/passwordInput/index.js +2 -1
  56. package/components/form/passwordInput/index.vue +269 -102
  57. package/components/form/radioInput/index.vue +143 -72
  58. package/components/form/rangeInput/index.vue +280 -167
  59. package/components/form/ratingInput/index.vue +57 -57
  60. package/components/form/selectInput/index.js +1 -3
  61. package/components/form/selectInput/index.vue +584 -296
  62. package/components/form/switchInput/index.vue +73 -59
  63. package/components/form/telInput/index.js +0 -1
  64. package/components/form/telInput/index.vue +238 -135
  65. package/components/form/textArea/index.vue +72 -35
  66. package/components/form/textEditor/index.vue +739 -0
  67. package/components/form/{text-editor → textEditor}/style.scss +8 -16
  68. package/components/form/textInput/index.vue +54 -32
  69. package/components/form/timeInput/index.vue +82 -55
  70. package/components/form/timeInput/range.vue +115 -94
  71. package/components/form/timeInput/timepicker.vue +382 -449
  72. package/components/form/uniqueInput/index.vue +105 -48
  73. package/components/form/unitInput/index.vue +139 -84
  74. package/components/formCreator/index.js +0 -1
  75. package/components/formCreator/index.vue +314 -148
  76. package/components/highlight/index.vue +41 -25
  77. package/components/highlight/style.scss +2 -2
  78. package/components/highlight/{mixin.js → useHighlight.js} +181 -160
  79. package/components/icon/index.vue +79 -33
  80. package/components/img/index.vue +250 -147
  81. package/components/img/preview.vue +180 -198
  82. package/components/img/svgImg.vue +42 -39
  83. package/components/index.js +5 -20
  84. package/components/infinite/index.js +3 -3
  85. package/components/infinite/index.vue +290 -66
  86. package/components/map/index.vue +428 -261
  87. package/components/map/route.vue +794 -487
  88. package/components/map/select.vue +118 -58
  89. package/components/menu/index.vue +206 -94
  90. package/components/meta/meta.js +26 -3
  91. package/components/modal/index.vue +382 -156
  92. package/components/notify/index.vue +204 -86
  93. package/components/notify/notification.vue +38 -55
  94. package/components/progress/circle.vue +189 -70
  95. package/components/progress/line.vue +266 -46
  96. package/components/searchBox/index.js +1 -3
  97. package/components/searchBox/index.vue +194 -101
  98. package/components/skeleton/index.vue +45 -20
  99. package/components/slider/index.vue +319 -156
  100. package/components/swiper/index.vue +237 -108
  101. package/components/table/crud/footer.vue +77 -53
  102. package/components/table/crud/header.vue +71 -72
  103. package/components/table/crud/index.vue +629 -399
  104. package/components/table/index.vue +721 -278
  105. package/components/timeAgo/index.vue +145 -96
  106. package/components/tour/index.vue +338 -235
  107. package/components/tree/index.vue +235 -89
  108. package/components/tree/tree-element.vue +106 -106
  109. package/directive/animate/index.js +77 -0
  110. package/directive/clickOutSide/index.js +98 -0
  111. package/directive/drag/index.js +153 -0
  112. package/directive/index.js +11 -13
  113. package/directive/intersect/index.js +263 -0
  114. package/directive/mask/index.js +67 -0
  115. package/directive/parallax/index.js +78 -0
  116. package/directive/ripple/index.js +14 -0
  117. package/directive/scroll/index.js +272 -24
  118. package/directive/sortable/index.js +274 -0
  119. package/directive/title/index.js +75 -0
  120. package/directive/touch/index.js +268 -0
  121. package/index.js +11 -19
  122. package/package.json +5 -2
  123. package/plugins/validation/Validate.js +88 -79
  124. package/scripts/generate-docs.mjs +226 -0
  125. package/scripts/menu.mjs +240 -0
  126. package/scripts/parser.mjs +1086 -0
  127. package/style/_index.scss +7 -0
  128. package/style/app.scss +13 -65
  129. package/style/colors.scss +5 -22
  130. package/style/functions/index.scss +8 -0
  131. package/style/mixins/index.scss +17 -5
  132. package/style/variables/base.scss +155 -178
  133. package/style/variables/color.scss +0 -12
  134. package/style/variables/utilities.scss +0 -180
  135. package/tools/helper.js +0 -8
  136. package/tools/icons.js +7 -2
  137. package/tools/root.js +71 -0
  138. package/components/app/style.scss +0 -41
  139. package/components/app/toast/style.scss +0 -20
  140. package/components/avatar/style.scss +0 -32
  141. package/components/bar/bottomNav.js +0 -1
  142. package/components/bar/bottomNav.vue +0 -28
  143. package/components/bar/bottomNavigationCircle.js +0 -2
  144. package/components/bar/bottomNavigationCircle.vue +0 -99
  145. package/components/bar/scss/bottomNav.scss +0 -67
  146. package/components/bar/scss/toolbar.scss +0 -174
  147. package/components/bar/toolbar/index.js +0 -8
  148. package/components/bar/toolbar/index.vue +0 -35
  149. package/components/bar/toolbar/laptop.vue +0 -33
  150. package/components/bar/toolbar/menuChilds.vue +0 -41
  151. package/components/bar/toolbar/menuLaptop.vue +0 -41
  152. package/components/bar/toolbar/menuMob.vue +0 -39
  153. package/components/bar/toolbar/mixin.js +0 -43
  154. package/components/bar/toolbar/mobile.vue +0 -34
  155. package/components/breadcrumb/bredcrumbItem.vue +0 -39
  156. package/components/breadcrumb/index.js +0 -3
  157. package/components/breadcrumb/index.vue +0 -71
  158. package/components/breadcrumb/style.scss +0 -51
  159. package/components/button/style.scss +0 -411
  160. package/components/card/style.scss +0 -86
  161. package/components/chart/chart.js +0 -1
  162. package/components/chart/chart.vue +0 -69
  163. package/components/chart/worldMap.js +0 -2
  164. package/components/chart/worldMap.vue +0 -1112
  165. package/components/chat/MessageList.vue +0 -163
  166. package/components/chat/chatInput.vue +0 -150
  167. package/components/chat/chatMsg.vue +0 -276
  168. package/components/chat/index.js +0 -11
  169. package/components/chat/index.vue +0 -113
  170. package/components/chip/index.js +0 -3
  171. package/components/chip/index.vue +0 -77
  172. package/components/chip/style.scss +0 -199
  173. package/components/codeEditor/mixin.js +0 -145
  174. package/components/countdown/index.js +0 -1
  175. package/components/countdown/index.vue +0 -105
  176. package/components/form/colorInput/mixin.js +0 -132
  177. package/components/form/fileInput/file.js +0 -148
  178. package/components/form/telInput/assets/flags.png +0 -0
  179. package/components/form/telInput/assets/flags@2x.png +0 -0
  180. package/components/form/text-editor/index.vue +0 -705
  181. package/components/icon/style.scss +0 -17
  182. package/components/infinite/div.js +0 -6
  183. package/components/infinite/div.vue +0 -193
  184. package/components/infinite/page.js +0 -3
  185. package/components/infinite/page.vue +0 -105
  186. package/components/list/index.js +0 -3
  187. package/components/list/index.vue +0 -122
  188. package/components/list/style.scss +0 -66
  189. package/components/message/index.js +0 -4
  190. package/components/message/index.vue +0 -40
  191. package/components/modal/style.scss +0 -146
  192. package/components/nestable/NestableItem.vue +0 -307
  193. package/components/nestable/editable.js +0 -44
  194. package/components/nestable/index.js +0 -1
  195. package/components/nestable/index.vue +0 -226
  196. package/components/nestable/methods.js +0 -416
  197. package/components/progress/style.scss +0 -229
  198. package/components/table/style.scss +0 -338
  199. package/components/tabs/index.js +0 -3
  200. package/components/tabs/index.vue +0 -151
  201. package/components/timeline/index.js +0 -6
  202. package/components/timeline/index.vue +0 -76
  203. package/directive/resize/index.js +0 -30
  204. package/directive/skeleton/index.js +0 -27
  205. package/directive/skeleton/style.scss +0 -37
  206. package/plugins/request/Request.js +0 -68
  207. package/style/animation.scss +0 -94
  208. package/style/style.scss +0 -8
  209. package/tools/rootable.js +0 -75
  210. /package/components/form/{text-editor → textEditor}/index.js +0 -0
  211. /package/components/form/{text-editor → textEditor}/preview.js +0 -0
  212. /package/components/form/{text-editor → textEditor}/preview.vue +0 -0
@@ -1,216 +1,380 @@
1
1
  <template>
2
- <div ref="uploader" class="image-card elevation-lg br-md">
2
+ <div ref="uploader" class="image-card br-md">
3
3
  <div class="file-holder text-center">
4
- <div class="image-canvas" v-if="file||modelValue">
5
- <r-btn icon class="image-close color-white">
6
- <r-icon @click.prevent="fileDelete()" class="color-error-text" v-html="$r.icons.delete"></r-icon>
4
+ <div v-if="file || modelValue" class="image-canvas">
5
+ <r-btn class="image-close color-white" icon size="xs">
6
+ <r-icon @click.prevent="fileDelete()" class="color-error-text"
7
+ v-html="$r.icons.delete"></r-icon>
7
8
  </r-btn>
8
9
  <r-progress-circle
9
- :indeterminate=false
10
- :modelValue="uploadPercentage"
11
- :width="2"
12
- class="image-progress"
13
- size="50"
10
+ :indeterminate="false"
11
+ :model-value="uploadPercentage"
12
+ :width="2"
13
+ class="image-progress"
14
+ size="50"
14
15
  >
15
16
  {{ `% ${uploadPercentage}` }}
16
17
  </r-progress-circle>
17
- <r-btn :href="fileLink" class="image-copy" icon target="_blank">
18
- <r-icon v-html="$r.icons.eye"></r-icon>
18
+ <r-btn :href="fileLink" class="image-copy color-white" icon size="xs" target="_blank">
19
+ <r-icon class="color-black-text" v-html="$r.icons.eye"></r-icon>
19
20
  </r-btn>
20
- <img v-if="isImg()" :class="`image ${imageStatus} `" :src="getUrl(file)">
21
+ <img v-if="isImg" :class="`image ${imageStatus} `" :src="getUrl(file)">
21
22
  <r-icon v-else
22
23
  class="file" width="100" height="100" v-html="$r.icons.file"
23
24
  :class="{'color-one-text':uploadPercentage===100}"
24
25
  ></r-icon>
25
26
  </div>
26
27
  <div class="file-meta pa-1" v-if="meta && uploadPercentage===100">
27
- <r-text-input :label="$t(m,'renusify')" v-model="metaList[m]" @update:model-value="emit"
28
- v-for="(m,k) in meta" :key="k"
29
- :rules="metaRequired?['required']:[]"></r-text-input>
28
+ <r-text-input
29
+ v-for="(m,k) in meta"
30
+ :key="k"
31
+ v-model="metaList[m]"
32
+ :label="$t(m,'renusify')"
33
+ :rules="metaRequired?['required']:[]"
34
+ @update:model-value="emitFileLink"
35
+ ></r-text-input>
30
36
  </div>
31
37
  </div>
32
- <r-icon @click.prevent.stop="pickFile"
33
- class="cursor-pointer w-full h-full d-flex h-center v-center color-one-text" width="100" height="100"
34
- v-html="$r.icons.plus"
35
- v-if="showAdd"></r-icon>
36
- <input :accept="accept"
37
- @change="addFile()"
38
- ref="file"
39
- style="display: none"
40
- type="file"
41
- v-if="showFile"
38
+
39
+ <r-icon
40
+ v-if="showAdd"
41
+ class="pick-icon cursor-pointer d-flex h-center v-center color-one-text"
42
+ height="100"
43
+ width="100"
44
+ v-html="$r.icons.plus"
45
+ @click.prevent.stop="pickFile"
46
+ ></r-icon>
47
+ <input
48
+ v-if="showFile"
49
+ ref="fileInput"
50
+ :accept="accept"
51
+ style="display: none"
52
+ type="file"
53
+ @change="addFile"
42
54
  >
43
- <r-modal v-model="showCrop" maxWidth="300px">
44
- <r-cropper v-if="wPH&&file" :imgSrc="file" :selectImg="false" :w-p-h="wPH" get-blob showCropped
45
- @cropped="file=$event,checkSave()"></r-cropper>
55
+ <r-modal v-model="showCrop" max-width="300px" no-close-btn>
56
+ <r-cropper
57
+ v-if="wPH && file"
58
+ :img-src="file"
59
+ :select-img="false"
60
+ :w-p-h="wPH || 1"
61
+ get-blob
62
+ show-cropped
63
+ @cropped="handleCropped"
64
+ ></r-cropper>
46
65
  </r-modal>
47
66
  </div>
48
67
  </template>
49
68
 
50
- <script>
51
- import file from "./file.js";
52
-
53
- export default {
54
- name: 'inputFile',
55
- mixins: [file],
56
- props: {
57
- accept: {
58
- default: '*',
59
- type: String
60
- },
61
- wPH: [Number, String, Array],
62
- maxFileSize: Number,
63
- uploadLink: {
64
- type: String,
65
- required: true
66
- },
67
- modelValue: {
68
- default: null,
69
- type: [String, Object]
70
- },
71
- meta: {
72
- type: Array,
73
- default: null
74
- },
75
- metaRequired: Boolean
69
+ <script setup>
70
+ import { ref, computed, watch, onMounted, nextTick, inject } from 'vue'
71
+
72
+ const props = defineProps({
73
+ accept: {
74
+ default: '*',
75
+ type: String
76
76
  },
77
- emits: ['file-link', 'select'],
78
- data() {
79
- return {
80
- showAdd: true,
81
- showFile: true,
82
- showCrop: false,
83
- metaList: {}
84
- }
77
+ wPH: [Number, String, Array],
78
+ maxFileSize: Number,
79
+ uploadLink: {
80
+ type: String,
81
+ required: true
85
82
  },
86
- created() {
87
- this.setValue()
83
+ modelValue: {
84
+ default: null,
85
+ type: [String, Object]
88
86
  },
89
- methods: {
90
- setValue() {
91
- if (this.modelValue) {
92
- this.fileLink = this.$helper.fix_url(this.meta ? this.modelValue['url'] : this.modelValue)
93
- this.metaList = this.meta ? this.modelValue['meta'] : {}
94
- this.showAdd = false
95
- this.imageStatus = 'finished'
96
- this.uploadPercentage = 100
97
- this.emit()
98
- }
99
- },
100
- getUrl(value) {
101
- if (this.modelValue) {
102
- return this.fileLink
103
- } else {
104
- return URL.createObjectURL(value)
105
- }
106
- },
107
- isImg() {
108
- let is = false
109
- let image = this.accept.split('/')
110
- is = image[0] === 'image'
111
- if (!is) {
112
- const p = this.fileLink.split('.')
113
- is = ['jpg', 'jpeg', 'png', 'gif', 'svg'].includes(p[p.length - 1])
114
- }
115
- return is
116
- },
117
- emit() {
118
- if (this.meta) {
119
- this.$emit('file-link', {'url': this.fileLink, 'meta': this.metaList})
120
- } else {
121
- this.$emit('file-link', this.fileLink)
122
- }
123
- this.$emit('select', true)
124
- }
87
+ meta: {
88
+ type: Array,
89
+ default: null
90
+ },
91
+ metaRequired: Boolean,
92
+ headers: Object
93
+ })
94
+
95
+ const emit = defineEmits(['file-link', 'select', 'delete', 'update:modelValue'])
96
+
97
+ // Refs
98
+ const uploader = ref(null)
99
+ const fileInput = ref(null)
100
+ const showAdd = ref(true)
101
+ const showFile = ref(true)
102
+ const showCrop = ref(false)
103
+ const metaList = ref({})
104
+ const imageStatus = ref('inProgress')
105
+ const fileLink = ref('')
106
+ const file = ref(null)
107
+ const file_type = ref(null)
108
+ const uploadPercentage = ref(0)
109
+ const $axios = inject('axios')
110
+ const $helper = inject('renusify').$helper
111
+ let CancelTokenSource = null
125
112
 
113
+ // Computed properties
114
+ const isImg = computed(() => {
115
+ if (!fileLink.value) return false
116
+ const p = fileLink.value.split('.')
117
+ const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'bmp', 'tiff']
118
+ const extension = p[p.length - 1].toLowerCase()
119
+ return imageExtensions.includes(extension)
120
+ })
121
+
122
+ // Methods
123
+ const createCancelToken = () => {
124
+ if ($axios?.CancelToken) {
125
+ CancelTokenSource = $axios.CancelToken.source()
126
126
  }
127
127
  }
128
- </script>
129
128
 
130
- <style lang="scss">
131
- @use "../../../style/variables/base";
129
+ const addFile = () => {
130
+ if (!fileInput.value?.files?.[0]) return
132
131
 
133
- .#{base.$prefix}file-uploader {
134
- .image-card {
135
- position: relative;
136
- width: auto;
137
- min-width: 150px;
138
- min-height: 200px;
132
+ createCancelToken()
133
+ file.value = fileInput.value.files[0]
134
+ file_type.value = file.value.type
139
135
 
140
- background-color: white;
136
+ const imgs = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/bmp', 'image/tiff']
141
137
 
138
+ if (props.wPH === undefined || !imgs.includes(file_type.value)) {
139
+ checkSave()
140
+ } else {
141
+ showCrop.value = true
142
+ }
142
143
 
143
- .file-meta {
144
- width: 250px;
145
- }
144
+ showAdd.value = false
145
+ }
146
146
 
147
- .fails {
148
- -webkit-filter: grayscale(100%);
149
- filter: grayscale(100%);
150
- }
147
+ const pickFile = () => {
148
+ fileInput.value?.click()
149
+ }
151
150
 
152
- .inProgress {
153
- -webkit-filter: blur(2px);
154
- filter: blur(2px);
155
- }
151
+ const fileDelete = async () => {
152
+ if (CancelTokenSource) {
153
+ CancelTokenSource.cancel()
154
+ }
156
155
 
157
- .finished {
158
- -webkit-filter: blur(0px);
159
- filter: blur(0px);
160
- }
156
+ try {
157
+ await deleteImage()
158
+ showFile.value = false
159
+ await nextTick(() => {
160
+ showFile.value = true
161
+ })
161
162
 
162
- .file {
163
- left: 0;
164
- right: 0;
165
- position: absolute;
166
- top: 0;
167
- bottom: 0;
168
- }
163
+ file.value = null
164
+ metaList.value = {}
165
+ uploadPercentage.value = 0
166
+ showAdd.value = true
169
167
 
170
- .image {
171
- width: auto;
172
- min-width: 150px;
173
- height: 200px;
174
- z-index: -2;
175
- opacity: 0.8;
176
- max-width: 100%;
177
- }
168
+ emit('delete', true)
169
+ emit('file-link', null)
170
+ } catch (error) {
171
+ console.error('Delete error:', error)
172
+ }
173
+ }
178
174
 
179
- .icon-100 {
180
- width: 100px;
181
- height: 100px;
182
- }
175
+ const checkSave = () => {
176
+ if (!file.value) return
183
177
 
184
- .image-canvas {
185
- width: auto;
186
- min-width: 150px;
187
- height: 200px;
188
- position: relative;
189
- background-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
178
+ // Check file size
179
+ if (props.maxFileSize && file.value.size > props.maxFileSize) {
180
+ if (CancelTokenSource) {
181
+ CancelTokenSource.cancel()
190
182
  }
183
+ console.error('max file size must be:', props.maxFileSize)
184
+ console.error('current file size is:', file.value.size)
191
185
 
192
- .image-close {
193
- cursor: pointer;
194
- position: absolute;
195
- left: 5px;
196
- top: 5px;
197
- z-index: 1;
186
+ // Using $toast via window or global property
187
+ if (window.$toast || inject('$toast')) {
188
+ const toast = window.$toast || inject('$toast')
189
+ const t = window.$t || inject('$t')
190
+ toast(t(['max_allow_size', [props.maxFileSize / 1024]], 'renusify'))
198
191
  }
192
+ return
193
+ }
194
+
195
+ const imgs = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/bmp', 'image/tiff']
199
196
 
200
- .image-progress {
201
- z-index: 1;
202
- position: absolute;
203
- right: 5px;
204
- top: 5px;
205
- color: white;
197
+ // Check image aspect ratio if needed
198
+ if (props.wPH !== undefined && imgs.includes(file_type.value)) {
199
+ const img = new Image()
200
+ const objectUrl = URL.createObjectURL(file.value)
201
+
202
+ // Calculate allowed aspect ratios
203
+ const allowedWPH = calculateAllowedWPH(props.wPH)
204
+
205
+ img.onload = function() {
206
+ const currentWPH = parseFloat((this.width / this.height).toFixed(4))
207
+
208
+ if (!allowedWPH.includes(currentWPH)) {
209
+ if (CancelTokenSource) {
210
+ CancelTokenSource.cancel()
211
+ }
212
+
213
+ // Using $toast via window or global property
214
+ if (window.$toast || inject('$toast')) {
215
+ const toast = window.$toast || inject('$toast')
216
+ const t = window.$t || inject('$t')
217
+ toast(t(['image_w_p_h', [props.wPH]], 'renusify'))
218
+ }
219
+
220
+ console.error('width per height must be:', props.wPH, allowedWPH)
221
+ console.error('current width per height is:', currentWPH)
222
+ }
223
+
224
+ URL.revokeObjectURL(objectUrl)
225
+ saveImage()
206
226
  }
207
227
 
208
- .image-copy {
209
- z-index: 1;
210
- position: absolute;
211
- left: 5px;
212
- bottom: 5px;
228
+ img.src = objectUrl
229
+ return
230
+ }
231
+
232
+ saveImage()
233
+ }
234
+
235
+ const calculateAllowedWPH = (wphInput) => {
236
+ const wphArray = []
237
+
238
+ if (Array.isArray(wphInput)) {
239
+ wphInput.forEach((item) => {
240
+ const strItem = item.toString()
241
+ if (strItem.includes('/')) {
242
+ const parts = strItem.split('/')
243
+ if (parts.length === 2) {
244
+ wphArray.push(parseFloat(parts[0]) / parseFloat(parts[1]))
245
+ } else {
246
+ wphArray.push(parseFloat(strItem))
247
+ }
248
+ } else {
249
+ wphArray.push(parseFloat(strItem))
250
+ }
251
+ })
252
+ } else {
253
+ const strItem = wphInput.toString()
254
+ if (strItem.includes('/')) {
255
+ const parts = strItem.split('/')
256
+ if (parts.length === 2) {
257
+ wphArray.push(parseFloat((parseFloat(parts[0]) / parseFloat(parts[1])).toFixed(4)))
258
+ } else {
259
+ wphArray.push(parseFloat(strItem))
260
+ }
261
+ } else {
262
+ wphArray.push(parseFloat(strItem))
213
263
  }
214
264
  }
265
+
266
+ return wphArray
267
+ }
268
+
269
+ const saveImage = async () => {
270
+ if (!file.value) return
271
+
272
+ imageStatus.value = 'inProgress'
273
+
274
+ const formData = new FormData()
275
+ formData.append('file', file.value, file.value.name)
276
+
277
+ let headers = props.headers || {}
278
+ headers['Content-Type'] = 'multipart/form-data'
279
+
280
+ let link = props.uploadLink
281
+ if (props.maxFileSize) {
282
+ const separator = link.includes('?') ? '&' : '?'
283
+ link += `${separator}max_size=${props.maxFileSize}`
284
+ }
285
+
286
+ try {
287
+ const response = await $axios.post(link, formData, {
288
+ headers,
289
+ onUploadProgress: (progressEvent) => {
290
+ if (progressEvent.total) {
291
+ uploadPercentage.value = Math.min(
292
+ parseInt(Math.floor((progressEvent.loaded * 100) / progressEvent.total)),
293
+ 98
294
+ )
295
+ }
296
+ },
297
+ cancelToken: CancelTokenSource?.token
298
+ })
299
+
300
+ fileLink.value = response.data.link
301
+ uploadPercentage.value = 100
302
+ emitFileLink()
303
+ imageStatus.value = 'finished'
304
+ } catch (error) {
305
+ imageStatus.value = 'fails'
306
+ uploadPercentage.value = 0
307
+ console.error('Upload error:', error)
308
+ }
215
309
  }
216
- </style>
310
+
311
+ const deleteImage = async () => {
312
+ if (!fileLink.value) return
313
+
314
+ try {
315
+ const response = await $axios.delete(props.uploadLink, {
316
+ data: { link: fileLink.value },
317
+ headers: props.headers
318
+ })
319
+ return response
320
+ } catch (error) {
321
+ console.error('Delete request error:', error)
322
+ throw error
323
+ }
324
+ }
325
+
326
+ const handleCropped = (croppedFile) => {
327
+ file.value = croppedFile
328
+ showCrop.value = false
329
+ checkSave()
330
+ }
331
+
332
+ const setValue = (value) => {
333
+ if (value) {
334
+ const fixUrl = $helper?.fix_url || ((url) => url)
335
+ fileLink.value = props.meta ? fixUrl(value['url']) : fixUrl(value)
336
+ metaList.value = props.meta ? value['meta'] : {}
337
+ showAdd.value = false
338
+ imageStatus.value = 'finished'
339
+ uploadPercentage.value = 100
340
+ emitFileLink()
341
+ }
342
+ }
343
+
344
+ const getUrl = (value) => {
345
+ if (props.modelValue) {
346
+ return fileLink.value
347
+ } else if (value) {
348
+ return URL.createObjectURL(value)
349
+ }
350
+ return ''
351
+ }
352
+
353
+ const emitFileLink = () => {
354
+ if (props.meta) {
355
+ emit('file-link', { 'url': fileLink.value, 'meta': metaList.value })
356
+ } else {
357
+ emit('file-link', fileLink.value)
358
+ }
359
+ emit('select', true)
360
+ }
361
+
362
+ // Watch for modelValue changes
363
+
364
+ watch(() => props.modelValue, (newVal, oldVal) => {
365
+ if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
366
+ setValue(newVal)
367
+ }
368
+ }, { immediate: true })
369
+
370
+ // Initialize
371
+ onMounted(() => {
372
+ createCancelToken()
373
+ })
374
+
375
+ // Expose methods if needed
376
+ defineExpose({
377
+ fileDelete,
378
+ pickFile
379
+ })
380
+ </script>