bfg-common 1.4.413 → 1.4.415

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.
@@ -2831,6 +2831,9 @@
2831
2831
  },
2832
2832
  "feedback": {
2833
2833
  "additionalDetailsHelp": "Даведка па дадатковых звестках",
2834
- "additionalDetailsTooltip": "Каб атрымаць дадатковую інфармацыю, вы можаце альбо зрабіць скрыншот экрана, альбо загрузіць выяву ў фармаце .png або .jpeg."
2834
+ "additionalDetailsTooltip": "Каб атрымаць дадатковую інфармацыю, вы можаце альбо зрабіць скрыншот экрана, альбо загрузіць выяву ў фармаце .png або .jpeg.",
2835
+ "annotate": "Анатаваць",
2836
+ "annotateScreenshot": "Анатаваць скрыншот",
2837
+ "annotateImage": "Анатаваць малюнак"
2835
2838
  }
2836
2839
  }
@@ -2835,6 +2835,9 @@
2835
2835
  },
2836
2836
  "feedback": {
2837
2837
  "additionalDetailsHelp": "Additional Details Help",
2838
- "additionalDetailsTooltip": "For additional details, you can either take a screenshot of your screen or upload an image in .png or .jpeg format."
2838
+ "additionalDetailsTooltip": "For additional details, you can either take a screenshot of your screen or upload an image in .png or .jpeg format.",
2839
+ "annotate": "Annotate",
2840
+ "annotateScreenshot": "Annotate Screenshot",
2841
+ "annotateImage": "Annotate Image"
2839
2842
  }
2840
2843
  }
@@ -2835,6 +2835,9 @@
2835
2835
  },
2836
2836
  "feedback": {
2837
2837
  "additionalDetailsHelp": "Լրացուցիչ մանրամասներ Օգնություն",
2838
- "additionalDetailsTooltip": "Լրացուցիչ մանրամասների համար կարող եք կամ լուսանկարել ձեր էկրանը կամ վերբեռնել պատկեր .png կամ .jpeg ձևաչափով:"
2838
+ "additionalDetailsTooltip": "Լրացուցիչ մանրամասների համար կարող եք կամ լուսանկարել ձեր էկրանը կամ վերբեռնել պատկեր .png կամ .jpeg ձևաչափով:",
2839
+ "annotate": "Նշում",
2840
+ "annotateScreenshot": "Նշել սքրինշոթը",
2841
+ "annotateImage": "Նշել պատկերը"
2839
2842
  }
2840
2843
  }
@@ -2834,6 +2834,9 @@
2834
2834
  },
2835
2835
  "feedback": {
2836
2836
  "additionalDetailsHelp": "Қосымша мәліметтер анықтамасы",
2837
- "additionalDetailsTooltip": "Қосымша мәліметтер алу үшін экранның скриншотын түсіруге немесе суретті .png немесе .jpeg пішімінде жүктеп салуға болады."
2837
+ "additionalDetailsTooltip": "Қосымша мәліметтер алу үшін экранның скриншотын түсіруге немесе суретті .png немесе .jpeg пішімінде жүктеп салуға болады.",
2838
+ "annotate": "Аннотация жазу",
2839
+ "annotateScreenshot": "Скриншотқа түсініктеме жазу",
2840
+ "annotateImage": "Суретке түсініктеме жазу"
2838
2841
  }
2839
2842
  }
@@ -2836,6 +2836,9 @@
2836
2836
  },
2837
2837
  "feedback": {
2838
2838
  "additionalDetailsHelp": "Дополнительная информация Помощь",
2839
- "additionalDetailsTooltip": "Для получения дополнительной информации вы можете сделать снимок экрана или загрузить изображение в формате .png или .jpeg."
2839
+ "additionalDetailsTooltip": "Для получения дополнительной информации вы можете сделать снимок экрана или загрузить изображение в формате .png или .jpeg.",
2840
+ "annotate": "Аннотировать",
2841
+ "annotateScreenshot": "Аннотировать снимок экрана",
2842
+ "annotateImage": "Аннотировать изображение"
2840
2843
  }
2841
2844
  }
@@ -2833,6 +2833,9 @@
2833
2833
  },
2834
2834
  "feedback": {
2835
2835
  "additionalDetailsHelp": "其他详细信息帮助",
2836
- "additionalDetailsTooltip": "有关更多详细信息,您可以截取屏幕截图或上传 .png 或 .jpeg 格式的图像。"
2836
+ "additionalDetailsTooltip": "有关更多详细信息,您可以截取屏幕截图或上传 .png 或 .jpeg 格式的图像。",
2837
+ "annotate": "注释",
2838
+ "annotateScreenshot": "注释屏幕截图",
2839
+ "annotateImage": "注释图像"
2837
2840
  }
2838
2841
  }
@@ -1,4 +1,5 @@
1
1
  import type { UI_I_FeedbackForm } from '~/components/common/feedback/lib/models/interfaces'
2
+ // import type { UI_I_FeedbackCanvasOptions } from '~/components/common/layout/theHeader/feedback/new/lib/models/interfaces'
2
3
  export const feedbackDefaultFormFunc = (): UI_I_FeedbackForm => {
3
4
  return {
4
5
  description: '',
@@ -7,3 +8,10 @@ export const feedbackDefaultFormFunc = (): UI_I_FeedbackForm => {
7
8
  image: '', // base64
8
9
  }
9
10
  }
11
+
12
+ // export const feedbackCanvasDefaultOptions = (): UI_I_FeedbackCanvasOptions => {
13
+ // return {
14
+ // isAnnotateImage: false,
15
+ // hasTakeScreenshot: false,
16
+ // }
17
+ // }
@@ -2,40 +2,46 @@
2
2
  <Teleport to="body">
3
3
  <ui-modal
4
4
  show
5
- width="560px"
5
+ :width="!options.isAnnotateImage ? '560px' : '880px'"
6
6
  test-id="feedback-modal"
7
- :title="localization.common.sendFeedback"
7
+ :title="title"
8
8
  class="feedback"
9
9
  @hide="onHideModal"
10
10
  >
11
11
  <template #content>
12
12
  <ui-modal-block-standard>
13
- <common-layout-the-header-feedback-new-subtitle />
13
+ <template v-if="!options.isAnnotateImage">
14
+ <common-layout-the-header-feedback-new-subtitle />
14
15
 
15
- <common-layout-the-header-feedback-new-tabs
16
- v-model="selectedTab"
17
- class="metrics-tabs"
18
- />
19
-
20
- <div
21
- v-if="selectedTab === 'light-bulb'"
22
- class="feedback__visit-portal"
23
- >
24
- {{ localization.common.useOurExternalIdeasPortal }}
25
- </div>
26
-
27
- <template v-else>
28
- <common-layout-the-header-feedback-new-description
29
- v-model="feedbackForm.description"
30
- v-model:is-valid="isValidForm"
31
- :selected-tab="selectedTab"
16
+ <common-layout-the-header-feedback-new-tabs
17
+ v-model="selectedTab"
18
+ class="metrics-tabs"
32
19
  />
33
20
 
34
- <common-layout-the-header-feedback-new-email
35
- v-model="feedbackForm.email"
36
- />
21
+ <div
22
+ v-if="selectedTab === 'light-bulb'"
23
+ class="feedback__visit-portal"
24
+ >
25
+ {{ localization.common.useOurExternalIdeasPortal }}
26
+ </div>
27
+ </template>
37
28
 
38
- <common-layout-the-header-feedback-new-additional-details />
29
+ <template v-if="selectedTab !== 'light-bulb'">
30
+ <template v-if="!options.isAnnotateImage">
31
+ <common-layout-the-header-feedback-new-description
32
+ v-model="feedbackForm.description"
33
+ v-model:is-valid="isValidForm"
34
+ :selected-tab="selectedTab"
35
+ />
36
+
37
+ <common-layout-the-header-feedback-new-email
38
+ v-model="feedbackForm.email"
39
+ />
40
+ </template>
41
+
42
+ <common-layout-the-header-feedback-new-additional-details
43
+ v-model="options"
44
+ />
39
45
  </template>
40
46
  </ui-modal-block-standard>
41
47
  </template>
@@ -57,7 +63,7 @@
57
63
  <ui-button
58
64
  test-id="feedback-modal-submit-btn"
59
65
  size="md"
60
- :disabled="!selectedTab"
66
+ :disabled="isDisabledButton"
61
67
  min-width="96px"
62
68
  @click="onSubmit"
63
69
  >
@@ -80,6 +86,8 @@
80
86
  import type { UI_I_Localization } from '~/lib/models/interfaces'
81
87
  import type { UI_I_FeedbackForm } from '~/components/common/feedback/lib/models/interfaces'
82
88
  import type { UI_T_FeedbackTab } from '~/components/common/layout/theHeader/feedback/new/tabs/lib/models/types'
89
+ import type { UI_I_FeedbackCanvasOptions } from '~/components/common/layout/theHeader/feedback/new/lib/models/interfaces'
90
+ import { UI_E_FeedbackType } from '~/components/common/layout/theHeader/feedback/new/tabs/lib/models/enums'
83
91
 
84
92
  const feedbackForm = defineModel<UI_I_FeedbackForm>({ required: true })
85
93
  const emits = defineEmits<{
@@ -89,19 +97,47 @@ const emits = defineEmits<{
89
97
 
90
98
  const localization = computed<UI_I_Localization>(() => useLocal())
91
99
 
92
- const isValidForm = ref<boolean>(true)
93
100
  const selectedTab = ref<UI_T_FeedbackTab>()
101
+ const isValidForm = ref<boolean>(true)
102
+ const options = ref<UI_I_FeedbackCanvasOptions>({
103
+ isAnnotateImage: false,
104
+ hasTakeScreenshot: false,
105
+ })
106
+
107
+ const title = computed<string>(() => {
108
+ const { common, feedback } = localization.value
109
+
110
+ return !options.value.isAnnotateImage
111
+ ? common.sendFeedback
112
+ : options.value.hasTakeScreenshot
113
+ ? feedback.annotateScreenshot
114
+ : feedback.annotateImage
115
+ })
116
+ const modalFooterButtonNames = computed<string>(() => {
117
+ const { visitIdeasPortal, send, save } = localization.value.common
118
+
119
+ return options.value.isAnnotateImage
120
+ ? save
121
+ : selectedTab.value === 'light-bulb'
122
+ ? visitIdeasPortal
123
+ : send
124
+ })
94
125
 
95
- const modalFooterButtonNames = computed(() => {
96
- return selectedTab.value === 'light-bulb'
97
- ? localization.value.common.visitIdeasPortal
98
- : localization.value.common.send
126
+ const isDisabledButton = computed<boolean>(() => {
127
+ return !options.value.isAnnotateImage && !selectedTab.value
99
128
  })
100
129
 
101
130
  const onHideModal = (): void => {
102
- emits('hide')
131
+ !options.value.isAnnotateImage
132
+ ? emits('hide')
133
+ : (options.value.isAnnotateImage = false)
103
134
  }
104
135
  const onSubmit = (): void => {
136
+ if (options.value.isAnnotateImage) {
137
+ options.value.isAnnotateImage = false
138
+ return
139
+ }
140
+
105
141
  if (selectedTab.value === 'light-bulb') {
106
142
  const targetUrl = 'https://customer.aobfg.ru/' // Ваш URL
107
143
  window.open(targetUrl, '_blank')
@@ -111,24 +147,25 @@ const onSubmit = (): void => {
111
147
  isValidForm.value = !!feedbackForm.value.description
112
148
 
113
149
  if (!isValidForm.value) return
114
- emits('submit')
115
- }
116
- </script>
150
+ const canvasData = (
151
+ document.getElementById('feedbackImg') as HTMLCanvasElement
152
+ ).toDataURL()
153
+ const canvasBlankData = (
154
+ document.getElementById('feedbackImgBlank') as HTMLCanvasElement
155
+ ).toDataURL()
117
156
 
118
- <style lang="scss">
119
- :root {
120
- --description-color: #414b57;
121
- --link-visited-color: #5659b8;
122
- }
157
+ const image = canvasData.match(/base64,(.+)/)?.[1] || ''
158
+ feedbackForm.value.image = canvasData === canvasBlankData ? '' : image
159
+ feedbackForm.value.type = UI_E_FeedbackType[selectedTab.value]
123
160
 
124
- :root.dark-theme {
125
- --description-color: #adbbc4;
126
- --link-visited-color: #49afd9;
161
+ emits('submit')
127
162
  }
163
+ </script>
128
164
 
165
+ <style lang="scss" scoped>
129
166
  .feedback {
130
167
  &__visit-portal {
131
- color: #4d5d69;
168
+ color: var(--feedback-text-color);
132
169
  font-size: 13px;
133
170
  font-weight: 400;
134
171
  line-height: 15.73px;
@@ -139,3 +176,13 @@ const onSubmit = (): void => {
139
176
  }
140
177
  }
141
178
  </style>
179
+ <style lang="scss">
180
+ :root {
181
+ --feedback-text-color: #4d5d69;
182
+ --feedback-tooltip-close-color: #213444;
183
+ }
184
+ :root.dark-theme {
185
+ --feedback-text-color: #e9eaec;
186
+ --feedback-tooltip-close-color: #e9eaec;
187
+ }
188
+ </style>
@@ -1,14 +1,29 @@
1
1
  <template>
2
2
  <div class="additional-details">
3
- <common-layout-the-header-feedback-new-additional-details-headline />
3
+ <template v-if="!optionsModel.isAnnotateImage">
4
+ <common-layout-the-header-feedback-new-additional-details-headline />
4
5
 
5
- <div class="flex gap-4 button-container">
6
+ <ui-alert
7
+ v-if="optionsModel.hasTakeScreenshot"
8
+ test-id="additional-details-info-alert"
9
+ :messages="[localization.common.screenshotQualityMayVary]"
10
+ type="info"
11
+ class="additional-details__alert"
12
+ ></ui-alert>
13
+ </template>
14
+
15
+ <div
16
+ v-if="!optionsModel.hasTakeScreenshot"
17
+ class="flex gap-4 button-container"
18
+ >
6
19
  <ui-button
7
20
  test-id="feedback-take-screenshot-btn"
8
21
  size="md"
9
- type="grey"
22
+ type="default"
23
+ variant="outline"
10
24
  min-width="96px"
11
25
  class="take-screenshot"
26
+ @click="onTakeScreenshot"
12
27
  >
13
28
  <ui-icon
14
29
  name="take-screenshot"
@@ -22,7 +37,8 @@
22
37
  <ui-button
23
38
  test-id="feedback-upload-file-btn"
24
39
  size="md"
25
- type="grey"
40
+ type="default"
41
+ variant="outline"
26
42
  min-width="96px"
27
43
  class="upload-image"
28
44
  >
@@ -41,30 +57,392 @@
41
57
  type="file"
42
58
  accept=".png, .jpeg"
43
59
  data-id="feedback-file-load-input"
60
+ @change="onUploadFile"
61
+ />
62
+ </ui-button>
63
+ </div>
64
+
65
+ <div v-if="optionsModel.isAnnotateImage" class="drawer-btn-container">
66
+ <div>
67
+ <ui-button
68
+ test-id="feedback-use-red-marker-button"
69
+ size="sm"
70
+ type="default"
71
+ variant="outline"
72
+ class="btn marker"
73
+ @click="onUseRedMarker"
74
+ >
75
+ <ui-icon
76
+ name="marker"
77
+ width="16"
78
+ height="16"
79
+ class="feedback__btn-icon"
80
+ />
81
+ {{ localization.common.useRedMarker }}
82
+ </ui-button>
83
+
84
+ <ui-button
85
+ test-id="feedback-use-grey-marker-button"
86
+ size="sm"
87
+ type="default"
88
+ variant="outline"
89
+ class="btn eraser"
90
+ @click="onUseGrayEraser"
91
+ >
92
+ <ui-icon
93
+ name="grey-eraser"
94
+ width="16"
95
+ height="16"
96
+ class="feedback__btn-icon"
97
+ />
98
+ {{ localization.common.useGrayEraser }}
99
+ </ui-button>
100
+ <ui-button
101
+ test-id="feedback-undo-button"
102
+ size="sm"
103
+ type="default"
104
+ variant="outline"
105
+ class="btn undo"
106
+ @click="onUndoLast"
107
+ >
108
+ <ui-icon
109
+ name="reset"
110
+ width="16"
111
+ height="16"
112
+ class="feedback__btn-icon"
113
+ />
114
+ {{ localization.common.undo }}
115
+ </ui-button>
116
+ </div>
117
+
118
+ <ui-button
119
+ test-id="feedback-clear-all-button"
120
+ size="sm"
121
+ type="default"
122
+ variant="outline"
123
+ class="btn clear-all"
124
+ @click="clearAll"
125
+ >
126
+ <ui-icon
127
+ name="delete"
128
+ width="16"
129
+ height="16"
130
+ class="feedback__btn-icon"
44
131
  />
132
+ {{ localization.common.clearAll }}
45
133
  </ui-button>
46
134
  </div>
135
+
136
+ <div
137
+ id="feedbackImgWrap"
138
+ ref="feedbackImgWrap"
139
+ class="preview-container"
140
+ :class="{
141
+ disabled: !optionsModel.hasTakeScreenshot,
142
+ annotate: optionsModel.isAnnotateImage,
143
+ }"
144
+ >
145
+ <div class="preview-container__backdrop">
146
+ <div>
147
+ <ui-button
148
+ test-id="feedback-image-annotate-btn"
149
+ size="md"
150
+ type="default"
151
+ variant="outline"
152
+ class=""
153
+ @click="onAnnotateImage"
154
+ >
155
+ <ui-icon
156
+ name="annotate-icon"
157
+ width="16"
158
+ height="16"
159
+ class="feedback__btn-icon"
160
+ />
161
+ {{ localization.feedback.annotate }}
162
+ </ui-button>
163
+
164
+ <ui-button
165
+ test-id="feedback-image-remove-btn"
166
+ size="md"
167
+ type="default"
168
+ variant="outline"
169
+ class=""
170
+ @click="onRemoveScreenshot"
171
+ >
172
+ <ui-icon
173
+ name="delete"
174
+ width="16"
175
+ height="16"
176
+ class="feedback__btn-icon"
177
+ />
178
+ {{ localization.common.remove }}
179
+ </ui-button>
180
+ </div>
181
+ </div>
182
+ <canvas
183
+ id="feedbackImg"
184
+ ref="feedbackImg"
185
+ class="preview-container__image"
186
+ ></canvas>
187
+ <canvas id="feedbackImgBlank" style="display: none"></canvas>
188
+ </div>
47
189
  </div>
48
190
  </template>
49
191
 
50
192
  <script lang="ts" setup>
193
+ import html2canvas from 'html2canvas'
51
194
  import type { UI_I_Localization } from '~/lib/models/interfaces'
195
+ import type { UI_I_FeedbackCanvasOptions } from '~/components/common/layout/theHeader/feedback/new/lib/models/interfaces'
196
+
197
+ const optionsModel = defineModel<UI_I_FeedbackCanvasOptions>({ required: true })
198
+ const emits = defineEmits<{
199
+ (event: 'screen-shot', value: any): void
200
+ }>()
52
201
 
53
202
  const localization = computed<UI_I_Localization>(() => useLocal())
203
+
204
+ const isFileLoad = ref(null)
205
+ const feedbackImgWrap = ref()
206
+ const feedbackImg = ref()
207
+ const memoryParentModalDialog = ref<string>('')
208
+ const memoryParentMain = ref<string>('')
209
+
210
+ const drawingArray: any = []
211
+ let indexArray = 0 // index of feedbackImg itself
212
+ let isDrawing = false
213
+ let startDrawingX: number | null = null
214
+ let startDrawingY: number | null = null
215
+ let drawColor = ''
216
+ let drawWidth = ''
217
+
218
+ const onTakeScreenshot = (): void => {
219
+ optionsModel.value.hasTakeScreenshot = true
220
+ const value = {
221
+ width: window.outerWidth + 'px',
222
+ }
223
+
224
+ emits('screen-shot', value)
225
+ const parentMain = document.getElementById('feedbackId')
226
+ const parentModalDialog = document.getElementById('feedback-modal-dialog-Id')
227
+ if (!parentMain || !parentModalDialog) return
228
+
229
+ const display = parentMain.style.display
230
+ memoryParentMain.value = parentMain.style.display
231
+ parentMain.style.display = 'none'
232
+ html2canvas(document.body).then(function (thisCanvas) {
233
+ parentMain.style.display = display
234
+ memoryParentMain.value = parentMain.style.width
235
+ memoryParentModalDialog.value = parentModalDialog.style.width
236
+ parentMain.style.width = window.outerWidth + 'px'
237
+ parentModalDialog.style.width = window.outerWidth + 'px'
238
+ parentModalDialog.style.margin = '20px'
239
+ const context = feedbackImg.value.getContext('2d')
240
+ feedbackImg.value.width = thisCanvas.width
241
+ feedbackImg.value.height = thisCanvas.height
242
+ context.drawImage(
243
+ thisCanvas,
244
+ 0,
245
+ 0,
246
+ feedbackImg.value.width,
247
+ feedbackImg.value.height
248
+ )
249
+ drawingArray.length = 0
250
+ indexArray = 0
251
+ drawingArray.push(
252
+ context.getImageData(
253
+ 0,
254
+ 0,
255
+ feedbackImg.value.width,
256
+ feedbackImg.value.height
257
+ )
258
+ )
259
+ })
260
+ }
261
+ const onUploadFile = (): void => {
262
+ optionsModel.value.hasTakeScreenshot = true
263
+ if (!isFileLoad.value) return
264
+
265
+ const isFileRead = new FileReader()
266
+ if (!isFileRead) return
267
+
268
+ isFileRead.readAsDataURL(isFileLoad.value.files[0])
269
+ isFileRead.onload = (): void => {
270
+ const img = new Image()
271
+ if (!feedbackImg.value) return
272
+
273
+ const context = feedbackImg.value.getContext('2d')
274
+ img.onload = (): void => {
275
+ feedbackImg.value.width = img.width
276
+ feedbackImg.value.height = img.height
277
+ context.drawImage(img, 0, 0, img.width, img.height)
278
+ drawingArray.length = 0
279
+ indexArray = 0
280
+ drawingArray.push(
281
+ context.getImageData(
282
+ 0,
283
+ 0,
284
+ feedbackImg.value.width,
285
+ feedbackImg.value.height
286
+ )
287
+ )
288
+ const value = {
289
+ width: window.outerWidth + 'px',
290
+ }
291
+ emits('screen-shot', value)
292
+ const parentMain = document.getElementById('feedbackId')
293
+ const parentModalDialog = document.getElementById(
294
+ 'feedback-modal-dialog-Id'
295
+ )
296
+ if (!parentMain || !parentModalDialog) return
297
+
298
+ parentMain.style.width = window.outerWidth + 'px'
299
+ parentModalDialog.style.width = window.outerWidth + 'px'
300
+ parentModalDialog.style.margin = '20px'
301
+ }
302
+ img.src = isFileRead.result
303
+ }
304
+ }
305
+
306
+ const start = (event: MouseEvent): void => {
307
+ if (!drawColor) return
308
+ const context = feedbackImg.value.getContext('2d')
309
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
310
+ startDrawingX = event.pageX - canvasCoordinates.left
311
+ startDrawingY = event.pageY - canvasCoordinates.top
312
+ isDrawing = true
313
+ context.beginPath()
314
+ context.moveTo(
315
+ event.pageX - canvasCoordinates.left,
316
+ event.pageY - canvasCoordinates.top
317
+ )
318
+ event.preventDefault()
319
+ }
320
+ const draw = (event: MouseEvent): void => {
321
+ if (!drawColor) return
322
+ const context = feedbackImg.value.getContext('2d')
323
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
324
+ if (!isDrawing) return
325
+ context.lineTo(
326
+ event.pageX - canvasCoordinates.left,
327
+ event.pageY - canvasCoordinates.top
328
+ )
329
+ context.strokeStyle = drawColor
330
+ context.lineWidth = drawWidth
331
+ context.lineCap = 'round'
332
+ context.lineJoin = 'round'
333
+ context.stroke()
334
+ event.preventDefault()
335
+ }
336
+
337
+ const stop = (event: MouseEvent): void => {
338
+ if (!drawColor) return
339
+
340
+ const context = feedbackImg.value.getContext('2d')
341
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
342
+ if (!isDrawing) return
343
+
344
+ context.stroke()
345
+ context.closePath()
346
+ isDrawing = false
347
+ event.preventDefault()
348
+ if (
349
+ startDrawingX !== event.pageX - canvasCoordinates.left &&
350
+ startDrawingY !== event.pageY - canvasCoordinates.top
351
+ ) {
352
+ drawingArray.push(
353
+ context.getImageData(
354
+ 0,
355
+ 0,
356
+ feedbackImg.value.width,
357
+ feedbackImg.value.height
358
+ )
359
+ )
360
+ indexArray += 1
361
+ }
362
+ }
363
+ const onRemoveScreenshot = (): void => {
364
+ optionsModel.value.hasTakeScreenshot = false
365
+ const parentMain = document.getElementById('feedbackId')
366
+ const parentModalDialog = document.getElementById('feedback-modal-dialog-Id')
367
+ if (!parentMain || !parentModalDialog) return
368
+
369
+ parentMain.style.width = memoryParentMain.value
370
+ parentModalDialog.style.width = memoryParentModalDialog.value
371
+ const context = feedbackImg.value.getContext('2d')
372
+ context.fillStyle = 'green'
373
+ context.fillRect(0, 0, feedbackImg.value.width, feedbackImg.value.height)
374
+ feedbackImg.value.width = 0
375
+ feedbackImg.value.height = 0
376
+ feedbackImgWrap.value.style.width = 0 + 'px'
377
+ feedbackImgWrap.value.style.height = 0 + 'px'
378
+ const value = {
379
+ width: memoryParentModalDialog.value,
380
+ }
381
+ emits('screen-shot', value)
382
+ clearAll()
383
+ }
384
+
385
+ const clearAll = (): void => {
386
+ const context = feedbackImg.value.getContext('2d')
387
+ // drawColor = ''
388
+ // drawWidth = ''
389
+ if (indexArray <= 0) return
390
+ while (indexArray > 0) {
391
+ drawingArray.pop()
392
+ indexArray -= 1
393
+ context.putImageData(drawingArray[indexArray], 0, 0)
394
+ }
395
+ }
396
+
397
+ const onUseRedMarker = (): void => {
398
+ drawColor = '#f76945'
399
+ drawWidth = '5'
400
+ }
401
+ const onUseGrayEraser = (): void => {
402
+ drawColor = 'lightgray'
403
+ drawWidth = '14'
404
+ }
405
+
406
+ const onUndoLast = (): void => {
407
+ drawColor = ''
408
+ drawWidth = ''
409
+ const context = feedbackImg.value.getContext('2d')
410
+ if (indexArray > 0) {
411
+ indexArray -= 1
412
+ drawingArray.pop()
413
+ context.putImageData(drawingArray[indexArray], 0, 0)
414
+ }
415
+ }
416
+
417
+ onMounted(() => {
418
+ feedbackImg.value.addEventListener('touchstart', start, false)
419
+ feedbackImg.value.addEventListener('touchmove', draw, false)
420
+ feedbackImg.value.addEventListener('mousedown', start, false)
421
+ feedbackImg.value.addEventListener('mousemove', draw, false)
422
+ feedbackImg.value.addEventListener('touchend', stop, false)
423
+ feedbackImg.value.addEventListener('mouseup', stop, false)
424
+ feedbackImg.value.addEventListener('mouseout', stop, false)
425
+ })
426
+
427
+ onBeforeUnmount(() => {
428
+ onRemoveScreenshot()
429
+ feedbackImg.value.removeEventListener('touchstart', start, false)
430
+ feedbackImg.value.removeEventListener('touchmove', draw, false)
431
+ feedbackImg.value.removeEventListener('mousedown', start, false)
432
+ feedbackImg.value.removeEventListener('mousemove', draw, false)
433
+ feedbackImg.value.removeEventListener('touchend', stop, false)
434
+ feedbackImg.value.removeEventListener('mouseup', stop, false)
435
+ feedbackImg.value.removeEventListener('mouseout', stop, false)
436
+ })
437
+ const onAnnotateImage = (): void => {
438
+ optionsModel.value.isAnnotateImage = true
439
+ }
54
440
  </script>
55
441
 
56
442
  <style lang="scss" scoped>
57
443
  @import 'assets/scss/common/mixins.scss';
58
444
  .additional-details {
59
445
  .button-container {
60
- margin-top: 16px;
61
- .upload-image,
62
- .take-screenshot {
63
- color: #4d5d69;
64
- gap: 8px;
65
- border: 1px solid #e9ebed;
66
- }
67
-
68
446
  .upload-image {
69
447
  label {
70
448
  @include flex($align: center, $just: center);
@@ -80,5 +458,84 @@ const localization = computed<UI_I_Localization>(() => useLocal())
80
458
  }
81
459
  }
82
460
  }
461
+ .drawer-btn-container {
462
+ margin-bottom: 12px;
463
+ & > div {
464
+ display: flex;
465
+ align-items: center;
466
+ justify-content: space-between;
467
+ gap: 15px;
468
+ }
469
+ display: flex;
470
+ align-items: center;
471
+ justify-content: space-between;
472
+
473
+ .ui-btn {
474
+ width: initial;
475
+
476
+ &.clear-all {
477
+ color: #ea3223;
478
+ }
479
+ }
480
+ }
481
+
482
+ &__alert {
483
+ margin-bottom: 16px;
484
+ }
485
+ }
486
+ .preview-container {
487
+ width: 500px;
488
+ height: 280px;
489
+ position: relative;
490
+ &.annotate {
491
+ width: 100%;
492
+ height: 460px;
493
+ }
494
+ &.disabled {
495
+ display: none;
496
+ }
497
+
498
+ &__backdrop {
499
+ display: none;
500
+ position: absolute;
501
+ top: 0;
502
+ left: 0;
503
+ width: 100%;
504
+ height: 100%;
505
+ background: rgba(27, 42, 55, 0.32);
506
+ backdrop-filter: blur(1.5px);
507
+ border-radius: 8px;
508
+ transition: opacity 0.3s ease;
509
+ opacity: 0;
510
+
511
+ & > div {
512
+ display: flex;
513
+ align-items: center;
514
+ gap: 12px;
515
+ .ui-btn {
516
+ width: initial;
517
+
518
+ &:last-child {
519
+ color: #ea3223;
520
+ }
521
+ }
522
+ }
523
+ }
524
+
525
+ &__image {
526
+ width: inherit;
527
+ height: inherit;
528
+ border-radius: 8px;
529
+ .disabled & {
530
+ display: none;
531
+ }
532
+ }
533
+
534
+ &:hover:not(&.annotate) &__backdrop {
535
+ display: flex;
536
+ align-items: center;
537
+ justify-content: center;
538
+ opacity: 1;
539
+ }
83
540
  }
84
541
  </style>
@@ -18,7 +18,7 @@
18
18
  :elem-id="'feedback-additional-details-info-icon'"
19
19
  >
20
20
  <div class="common-widget-info">
21
- <div class="headline justify-between flex-align-center">
21
+ <div class="justify-between flex-align-center">
22
22
  <div class="flex-align-center">
23
23
  <ui-icon-icon3 name="info-2" width="16px" height="16px" />
24
24
  <span class="title">
@@ -54,31 +54,34 @@ const isShowInfo = ref<boolean>(false)
54
54
  @import 'assets/scss/common/mixins.scss';
55
55
  .headline {
56
56
  @include flex($align: center);
57
- margin-top: 16px;
57
+ margin: 32px 0 16px;
58
58
  &__label {
59
- line-height: 38px;
59
+ line-height: 19.36px;
60
60
  font-size: 16px;
61
61
  font-weight: 500;
62
- color: #4d5d69;
62
+ color: var(--feedback-text-color);
63
63
  margin-right: 8px;
64
64
  }
65
65
  .common-widget-info {
66
66
  padding: 16px;
67
-
68
67
  .title {
69
68
  font-size: 14px;
70
69
  font-weight: 500;
71
70
  line-height: 16.94px;
72
- color: var(--zabbix-text-color);
71
+ color: var(--feedback-text-color);
73
72
  margin-left: 8px;
74
73
  }
75
74
 
76
75
  .common-widget-info-description {
77
76
  font-size: 13px;
78
77
  line-height: 15.73px;
79
- color: var(--zabbix-text-color);
78
+ color: var(--feedback-text-color);
80
79
  margin-top: 12px;
81
80
  }
81
+
82
+ svg {
83
+ color: var(--feedback-tooltip-close-color);
84
+ }
82
85
  }
83
86
  }
84
87
  </style>
@@ -44,11 +44,11 @@ const descriptionErrorText = computed<boolean>(() => {
44
44
  .description {
45
45
  margin-top: 32px;
46
46
  &__title {
47
- line-height: 38px;
47
+ line-height: 19.36px;
48
48
  margin-bottom: 16px;
49
49
  font-size: 16px;
50
50
  font-weight: 500;
51
- color: #4d5d69;
51
+ color: var(--feedback-text-color);
52
52
  }
53
53
  :deep(.ui-main-textarea) {
54
54
  resize: none;
@@ -33,11 +33,11 @@ const emailErrorText = computed<string>(() => {
33
33
  .email {
34
34
  margin-top: 32px;
35
35
  &__title {
36
- line-height: 38px;
36
+ line-height: 19.36px;
37
37
  margin-bottom: 16px;
38
38
  font-size: 16px;
39
39
  font-weight: 500;
40
- color: #4d5d69;
40
+ color: var(--feedback-text-color);
41
41
  }
42
42
  }
43
43
  </style>
@@ -0,0 +1,4 @@
1
+ export interface UI_I_FeedbackCanvasOptions {
2
+ isAnnotateImage: boolean
3
+ hasTakeScreenshot: boolean
4
+ }
@@ -63,21 +63,24 @@ const isShowInfo = ref<boolean>(false)
63
63
  }
64
64
  .common-widget-info {
65
65
  padding: 16px;
66
-
67
66
  .title {
68
67
  font-size: 14px;
69
68
  font-weight: 500;
70
69
  line-height: 16.94px;
71
- color: var(--zabbix-text-color);
70
+ color: var(--feedback-text-color);
72
71
  margin-left: 8px;
73
72
  }
74
73
 
75
74
  .common-widget-info-description {
76
75
  font-size: 13px;
77
76
  line-height: 15.73px;
78
- color: var(--zabbix-text-color);
77
+ color: var(--feedback-text-color);
79
78
  margin-top: 12px;
80
79
  }
80
+
81
+ svg {
82
+ color: var(--feedback-tooltip-close-color);
83
+ }
81
84
  }
82
85
  }
83
86
  </style>
@@ -20,13 +20,12 @@
20
20
 
21
21
  <script setup lang="ts">
22
22
  import type { UI_I_Localization } from '~/lib/models/interfaces'
23
- import type { T_FeedbackTab } from '~/components/common/layout/theHeader/feedback/new/tabs/lib/models/types'
24
- // import type { I_Metric } from '~/components/layout/new/tabs/lib/models/interfaces'
23
+ import type { UI_T_FeedbackTab } from '~/components/common/layout/theHeader/feedback/new/tabs/lib/models/types'
25
24
  import { tabsFunc } from '~/components/common/layout/theHeader/feedback/new/tabs/lib/config/tabs'
26
25
 
27
26
  const localization = computed<UI_I_Localization>(() => useLocal())
28
27
 
29
- const selectedTab = defineModel<T_FeedbackTab>({ required: true })
28
+ const selectedTab = defineModel<UI_T_FeedbackTab>({ required: true })
30
29
  const tabs = computed<any[]>(() =>
31
30
  tabsFunc(localization.value, selectedTab.value)
32
31
  )
@@ -40,7 +39,7 @@ const tabs = computed<any[]>(() =>
40
39
  margin-bottom: 16px;
41
40
  font-size: 16px;
42
41
  font-weight: 500;
43
- color: #4d5d69;
42
+ color: var(--feedback-text-color);
44
43
  }
45
44
  &__container {
46
45
  display: flex;
@@ -50,17 +49,21 @@ const tabs = computed<any[]>(() =>
50
49
  :deep(.block) {
51
50
  width: max-content;
52
51
  padding: 10px 12px;
53
- color: #4d5d69;
52
+ color: var(--feedback-text-color);
53
+ background: var(--feedback-tab-bg-color);
54
+ border: 1px solid var(--feedback-tab-border-color);
55
+ box-shadow: none;
54
56
  cursor: pointer;
55
57
  }
58
+
56
59
  :deep(.block.selected) {
57
- border: 1.5px solid #008fd6;
58
- color: #008fd6;
60
+ border: 1.5px solid var(--feedback-tab-active-text-color);
61
+ color: var(--feedback-tab-active-text-color);
59
62
  cursor: default;
60
63
 
61
64
  .main-info,
62
65
  .main-info-label {
63
- color: #008fd6;
66
+ color: var(--feedback-tab-active-text-color);
64
67
  }
65
68
  }
66
69
 
@@ -77,3 +80,16 @@ const tabs = computed<any[]>(() =>
77
80
  }
78
81
  }
79
82
  </style>
83
+ <style lang="scss">
84
+ :root {
85
+ --feedback-tab-bg-color: #ffffff;
86
+ --feedback-tab-border-color: #e9ebed;
87
+ --feedback-tab-active-text-color: #008fd6;
88
+ }
89
+
90
+ :root.dark-theme {
91
+ --feedback-tab-bg-color: #1b2a373d;
92
+ --feedback-tab-border-color: #e9ebed1f;
93
+ --feedback-tab-active-text-color: #2ba2de;
94
+ }
95
+ </style>
@@ -1,9 +1,9 @@
1
1
  import type { UI_I_Localization } from '~/lib/models/interfaces'
2
- import type { T_FeedbackTab } from '~/components/common/layout/theHeader/feedback/new/tabs/lib/models/types'
2
+ import type { UI_T_FeedbackTab } from '~/components/common/layout/theHeader/feedback/new/tabs/lib/models/types'
3
3
 
4
4
  export const tabsFunc = (
5
5
  localization: UI_I_Localization,
6
- selectedTab: T_FeedbackTab
6
+ selectedTab: UI_T_FeedbackTab
7
7
  ): any[] => {
8
8
  return [
9
9
  {
@@ -0,0 +1,6 @@
1
+ export enum UI_E_FeedbackType {
2
+ 'warning-outline',
3
+ 'heart-outline',
4
+ WARNING,
5
+ 'light-bulb',
6
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bfg-common",
3
3
  "private": false,
4
- "version": "1.4.413",
4
+ "version": "1.4.415",
5
5
  "scripts": {
6
6
  "build": "nuxt build",
7
7
  "dev": "nuxt dev --port=3002",
@@ -1,17 +0,0 @@
1
- import type {
2
- T_MetricTab
3
- } from '~/components/common/pages/integration/zabbix/content/hosts/details/metrics/lib/models/types'
4
-
5
- export interface I_Metric {
6
- iconName: T_MetricTab
7
- label: string
8
- isSelected: boolean
9
- on: {
10
- label: string
11
- color: '#239332' | '#BDC3C7'
12
- }
13
- off: {
14
- label: string
15
- color: '#EA3223' | '#BDC3C7'
16
- }
17
- }