bfg-common 1.5.484 → 1.5.486

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.
@@ -1,460 +1,460 @@
1
- <template>
2
- <div
3
- :class="['window-container', { loading: props.loading }]"
4
- :style="{
5
- left: leftLocal + 'px',
6
- top: topLocal + 'px',
7
- width: widthLocal + 'px',
8
- height: heightLocal + 'px',
9
- }"
10
- >
11
- <div
12
- ref="headerEl"
13
- class="window-header"
14
- :style="{ height: headerHeight + 'px' }"
15
- >
16
- <slot name="header">
17
- <div class="window-title text-ellipsis">{{ props.title }}</div>
18
- </slot>
19
-
20
- <div class="flex-align-center gap-2">
21
- <button class="window-btn window-hide" @click="onCollapse">
22
- <ui-icon
23
- :name="collapseData.isCollapsed ? 'arrow' : 'check-line'"
24
- class="hide-icon"
25
- width="16"
26
- height="16"
27
- />
28
- </button>
29
- <button class="window-btn window-view-full-screen" @click="toggle">
30
- <ui-icon
31
- name="view-full-screen"
32
- class="view-full-screen-icon"
33
- width="14"
34
- height="14"
35
- />
36
- </button>
37
- <button class="window-btn window-close" @click="onHide">
38
- <ui-icon name="close" class="close-icon" width="16" height="16" />
39
- </button>
40
- </div>
41
- </div>
42
-
43
- <div ref="windowContent" class="window-content">
44
- <div v-show="props.loading" class="absolute-center">
45
- <ui-icon name="spinner" />
46
- </div>
47
- <slot></slot>
48
- <div v-show="isShowContentBlocker" class="content-blocker"></div>
49
- </div>
50
-
51
- <!-- Ручки для ресайза -->
52
- <div
53
- class="resize-handle resize-top"
54
- @mousedown="startResize($event, 'top')"
55
- ></div>
56
- <div
57
- class="resize-handle resize-right"
58
- @mousedown="startResize($event, 'right')"
59
- ></div>
60
- <div
61
- class="resize-handle resize-bottom"
62
- @mousedown="startResize($event, 'bottom')"
63
- ></div>
64
- <div
65
- class="resize-handle resize-left"
66
- @mousedown="startResize($event, 'left')"
67
- ></div>
68
- <div
69
- class="resize-handle resize-top-left"
70
- @mousedown="startResize($event, 'top-left')"
71
- ></div>
72
- <div
73
- class="resize-handle resize-top-right"
74
- @mousedown="startResize($event, 'top-right')"
75
- ></div>
76
- <div
77
- class="resize-handle resize-bottom-left"
78
- @mousedown="startResize($event, 'bottom-left')"
79
- ></div>
80
- <div
81
- class="resize-handle resize-bottom-right"
82
- @mousedown="startResize($event, 'bottom-right')"
83
- ></div>
84
- </div>
85
- </template>
86
-
87
- <script setup lang="ts">
88
- import { useDraggable, useFullscreen } from '@vueuse/core'
89
- import type { UI_I_WindowCollapsedData } from '~/components/atoms/window/lib/models/interfaces'
90
- import {
91
- minWidth,
92
- minHeight,
93
- headerHeight,
94
- windowPadding,
95
- } from '~/components/atoms/window/lib/config/config'
96
-
97
- const props = withDefaults(
98
- defineProps<{
99
- top: number
100
- left: number
101
- width: number
102
- height: number
103
- title: string
104
- loading?: boolean
105
- }>(),
106
- {
107
- loading: false,
108
- }
109
- )
110
- const emits = defineEmits<{
111
- (event: 'hide'): void
112
- }>()
113
-
114
- const windowContent = ref<any>(null)
115
- const { toggle } = useFullscreen(windowContent)
116
-
117
- const headerEl = ref(null)
118
- const isShowContentBlocker = ref<boolean>(false)
119
-
120
- const leftLocal = ref<number>(props.left)
121
- const topLocal = ref<number>(props.top - headerHeight)
122
- const widthLocal = ref<number>(Math.max(minWidth, props.width))
123
- const heightLocal = ref<number>(
124
- Math.max(minHeight, props.height + headerHeight)
125
- )
126
-
127
- const collapseData = ref<UI_I_WindowCollapsedData>({
128
- isCollapsed: false,
129
- cashTop: -1,
130
- cashLeft: -1,
131
- cashWidth: -1,
132
- cashHeight: -1,
133
- })
134
-
135
- // Используем vueuse для перетаскивания
136
- useDraggable(headerEl, {
137
- initialValue: { x: leftLocal.value, y: topLocal.value },
138
- onMove({ x: newX, y: newY }) {
139
- leftLocal.value = newX
140
- topLocal.value = newY
141
- },
142
- onStart() {
143
- isShowContentBlocker.value = true
144
- if (!collapseData.value.isCollapsed) {
145
- collapseData.value.cashTop = topLocal.value
146
- collapseData.value.cashLeft = leftLocal.value
147
- collapseData.value.cashWidth = widthLocal.value
148
- collapseData.value.cashHeight = heightLocal.value
149
- }
150
- },
151
- onEnd() {
152
- isShowContentBlocker.value = false
153
- fixPosition()
154
- },
155
- })
156
-
157
- const fixSize = (): void => {
158
- const globalWindowWidth = window.innerWidth
159
- const globalWindowHeight = window.innerHeight
160
-
161
- widthLocal.value = Math.min(
162
- globalWindowWidth - windowPadding * 2,
163
- widthLocal.value
164
- )
165
- heightLocal.value = Math.min(
166
- globalWindowHeight - windowPadding * 2,
167
- heightLocal.value
168
- )
169
- }
170
- const fixPosition = (): void => {
171
- const globalWindowWidth = window.innerWidth
172
- const globalWindowHeight = window.innerHeight
173
- let newX = leftLocal.value
174
- let newY = topLocal.value
175
-
176
- if (leftLocal.value + widthLocal.value > globalWindowWidth - windowPadding) {
177
- newX = globalWindowWidth - widthLocal.value - windowPadding
178
- } else if (leftLocal.value < windowPadding) {
179
- newX = windowPadding
180
- }
181
-
182
- if (topLocal.value + heightLocal.value / 2 > globalWindowHeight) {
183
- newY = globalWindowHeight - headerHeight
184
- collapseData.value.isCollapsed = true
185
- } else if (
186
- topLocal.value + heightLocal.value >
187
- globalWindowHeight - windowPadding
188
- ) {
189
- newY = globalWindowHeight - heightLocal.value - windowPadding
190
- collapseData.value.isCollapsed = false
191
- } else if (topLocal.value < windowPadding) {
192
- newY = windowPadding
193
- collapseData.value.isCollapsed = false
194
- } else {
195
- collapseData.value.isCollapsed = false
196
- }
197
-
198
- smoothMove(newX, newY)
199
- }
200
- const smoothMove = (newX: number, newY: number, duration = 100): void => {
201
- const startX = leftLocal.value
202
- const startY = topLocal.value
203
-
204
- // Время начала анимации
205
- const startTime = performance.now()
206
-
207
- // Функция анимации
208
- const animate = (currentTime: number): void => {
209
- // Прошедшее время с начала анимации
210
- const elapsedTime = currentTime - startTime
211
-
212
- // Прогресс анимации (от 0 до 1)
213
- const progress = Math.min(elapsedTime / duration, 1)
214
-
215
- // Вычисляем новые координаты с помощью линейной интерполяции
216
- leftLocal.value = startX + (newX - startX) * progress
217
- topLocal.value = startY + (newY - startY) * progress
218
-
219
- // Если анимация не завершена, продолжаем
220
- if (progress < 1) {
221
- requestAnimationFrame(animate)
222
- }
223
- }
224
-
225
- // Запускаем анимацию
226
- requestAnimationFrame(animate)
227
- }
228
-
229
- const onCollapse = (): void => {
230
- collapseData.value.isCollapsed = !collapseData.value.isCollapsed
231
-
232
- if (collapseData.value.isCollapsed) {
233
- collapseData.value.cashTop = topLocal.value
234
- collapseData.value.cashLeft = leftLocal.value
235
- collapseData.value.cashWidth = widthLocal.value
236
- collapseData.value.cashHeight = heightLocal.value
237
-
238
- const globalWindowWidth = window.innerWidth
239
- const globalWindowHeight = window.innerHeight
240
-
241
- widthLocal.value = minWidth
242
- // heightLocal.value = minHeight
243
- leftLocal.value = globalWindowWidth - widthLocal.value - windowPadding
244
- topLocal.value = globalWindowHeight - headerHeight
245
- fixPosition()
246
- } else {
247
- leftLocal.value = collapseData.value.cashLeft
248
- topLocal.value = collapseData.value.cashTop
249
- widthLocal.value = collapseData.value.cashWidth
250
- heightLocal.value = collapseData.value.cashHeight
251
- fixPosition()
252
- }
253
- }
254
-
255
- // Функция для ресайза
256
- const startResize = (e: any, direction: any): void => {
257
- e.preventDefault()
258
-
259
- const startX = e.clientX
260
- const startY = e.clientY
261
- const startWidth = widthLocal.value
262
- const startHeight = heightLocal.value
263
- const startLeft = leftLocal.value
264
- const startTop = topLocal.value
265
-
266
- const onMouseMove = (e: any): void => {
267
- const deltaX = e.clientX - startX
268
- const deltaY = e.clientY - startY
269
-
270
- if (direction.includes('right')) {
271
- widthLocal.value = Math.max(minWidth, startWidth + deltaX)
272
- }
273
- if (direction.includes('bottom')) {
274
- heightLocal.value = Math.max(minHeight, startHeight + deltaY)
275
- }
276
- if (direction.includes('left')) {
277
- const newWidth = Math.max(minWidth, startWidth - deltaX)
278
- if (newWidth !== widthLocal.value) {
279
- leftLocal.value = startLeft + deltaX
280
- widthLocal.value = newWidth
281
- }
282
- }
283
- if (direction.includes('top')) {
284
- const newHeight = Math.max(minHeight, startHeight - deltaY)
285
- if (newHeight !== heightLocal.value) {
286
- topLocal.value = startTop + deltaY
287
- heightLocal.value = newHeight
288
- }
289
- }
290
- fixSize()
291
- }
292
-
293
- const onMouseUp = (): void => {
294
- document.removeEventListener('mousemove', onMouseMove)
295
- document.removeEventListener('mouseup', onMouseUp)
296
- isShowContentBlocker.value = false
297
- fixPosition()
298
- }
299
-
300
- document.addEventListener('mousemove', onMouseMove)
301
- document.addEventListener('mouseup', onMouseUp)
302
- isShowContentBlocker.value = true
303
- }
304
-
305
- let resizeTimer: any = null
306
- const globalWindowResize = (): void => {
307
- clearTimeout(resizeTimer)
308
-
309
- resizeTimer = setTimeout(() => {
310
- fixSize()
311
- fixPosition()
312
- }, 250)
313
- }
314
- onMounted(() => {
315
- window.addEventListener('resize', globalWindowResize)
316
- fixSize()
317
- fixPosition()
318
- })
319
- onUnmounted(() => {
320
- window.removeEventListener('resize', globalWindowResize)
321
- })
322
-
323
- const onHide = (): void => {
324
- emits('hide')
325
- }
326
- </script>
327
-
328
- <style lang="scss">
329
- .window-container {
330
- position: absolute;
331
- border-radius: 6px;
332
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
333
- overflow: hidden;
334
- background-color: #fff;
335
- display: flex;
336
- flex-direction: column;
337
- //min-width: 300px;
338
- //min-height: 200px;
339
- z-index: var(--z-toast);
340
-
341
- &.loading {
342
- opacity: 0.5;
343
- }
344
-
345
- .window-header {
346
- background-color: #314351;
347
- color: white;
348
- padding: 6px 12px;
349
- cursor: move;
350
- user-select: none;
351
- display: flex;
352
- justify-content: space-between;
353
- align-items: center;
354
-
355
- .window-title {
356
- font-size: 13px;
357
- }
358
-
359
- .window-btn {
360
- background: none;
361
- border: none;
362
- color: #e4e4e4;
363
- cursor: pointer;
364
- width: 20px;
365
- height: 20px;
366
- display: flex;
367
- justify-content: center;
368
- align-items: center;
369
-
370
- &:hover {
371
- color: #ffffff;
372
- }
373
- }
374
- }
375
-
376
- .window-content {
377
- position: relative;
378
- flex-grow: 1;
379
-
380
- .content-blocker {
381
- position: absolute;
382
- top: 0;
383
- left: 0;
384
- width: 100%;
385
- height: 100%;
386
- z-index: 1;
387
- }
388
- }
389
-
390
- .resize-handle {
391
- position: absolute;
392
- background: transparent;
393
- z-index: 10;
394
-
395
- &.resize-top {
396
- top: -3px;
397
- left: 0;
398
- right: 0;
399
- height: 6px;
400
- cursor: n-resize;
401
- }
402
-
403
- &.resize-right {
404
- top: 0;
405
- right: -3px;
406
- bottom: 0;
407
- width: 6px;
408
- cursor: e-resize;
409
- }
410
-
411
- &.resize-bottom {
412
- bottom: -3px;
413
- left: 0;
414
- right: 0;
415
- height: 6px;
416
- cursor: s-resize;
417
- }
418
-
419
- &.resize-left {
420
- top: 0;
421
- left: -3px;
422
- bottom: 0;
423
- width: 6px;
424
- cursor: w-resize;
425
- }
426
-
427
- &.resize-top-left {
428
- top: -6px;
429
- left: -6px;
430
- width: 12px;
431
- height: 12px;
432
- cursor: nw-resize;
433
- }
434
-
435
- &.resize-top-right {
436
- top: -6px;
437
- right: -6px;
438
- width: 12px;
439
- height: 12px;
440
- cursor: ne-resize;
441
- }
442
-
443
- &.resize-bottom-left {
444
- bottom: -6px;
445
- left: -6px;
446
- width: 12px;
447
- height: 12px;
448
- cursor: sw-resize;
449
- }
450
-
451
- &.resize-bottom-right {
452
- bottom: -6px;
453
- right: -6px;
454
- width: 12px;
455
- height: 12px;
456
- cursor: se-resize;
457
- }
458
- }
459
- }
460
- </style>
1
+ <template>
2
+ <div
3
+ :class="['window-container', { loading: props.loading }]"
4
+ :style="{
5
+ left: leftLocal + 'px',
6
+ top: topLocal + 'px',
7
+ width: widthLocal + 'px',
8
+ height: heightLocal + 'px',
9
+ }"
10
+ >
11
+ <div
12
+ ref="headerEl"
13
+ class="window-header"
14
+ :style="{ height: headerHeight + 'px' }"
15
+ >
16
+ <slot name="header">
17
+ <div class="window-title text-ellipsis">{{ props.title }}</div>
18
+ </slot>
19
+
20
+ <div class="flex-align-center gap-2">
21
+ <button class="window-btn window-hide" @click="onCollapse">
22
+ <ui-icon
23
+ :name="collapseData.isCollapsed ? 'arrow' : 'check-line'"
24
+ class="hide-icon"
25
+ width="16"
26
+ height="16"
27
+ />
28
+ </button>
29
+ <button class="window-btn window-view-full-screen" @click="toggle">
30
+ <ui-icon
31
+ name="view-full-screen"
32
+ class="view-full-screen-icon"
33
+ width="14"
34
+ height="14"
35
+ />
36
+ </button>
37
+ <button class="window-btn window-close" @click="onHide">
38
+ <ui-icon name="close" class="close-icon" width="16" height="16" />
39
+ </button>
40
+ </div>
41
+ </div>
42
+
43
+ <div ref="windowContent" class="window-content">
44
+ <div v-show="props.loading" class="absolute-center">
45
+ <ui-icon name="spinner" />
46
+ </div>
47
+ <slot></slot>
48
+ <div v-show="isShowContentBlocker" class="content-blocker"></div>
49
+ </div>
50
+
51
+ <!-- Ручки для ресайза -->
52
+ <div
53
+ class="resize-handle resize-top"
54
+ @mousedown="startResize($event, 'top')"
55
+ ></div>
56
+ <div
57
+ class="resize-handle resize-right"
58
+ @mousedown="startResize($event, 'right')"
59
+ ></div>
60
+ <div
61
+ class="resize-handle resize-bottom"
62
+ @mousedown="startResize($event, 'bottom')"
63
+ ></div>
64
+ <div
65
+ class="resize-handle resize-left"
66
+ @mousedown="startResize($event, 'left')"
67
+ ></div>
68
+ <div
69
+ class="resize-handle resize-top-left"
70
+ @mousedown="startResize($event, 'top-left')"
71
+ ></div>
72
+ <div
73
+ class="resize-handle resize-top-right"
74
+ @mousedown="startResize($event, 'top-right')"
75
+ ></div>
76
+ <div
77
+ class="resize-handle resize-bottom-left"
78
+ @mousedown="startResize($event, 'bottom-left')"
79
+ ></div>
80
+ <div
81
+ class="resize-handle resize-bottom-right"
82
+ @mousedown="startResize($event, 'bottom-right')"
83
+ ></div>
84
+ </div>
85
+ </template>
86
+
87
+ <script setup lang="ts">
88
+ import { useDraggable, useFullscreen } from '@vueuse/core'
89
+ import type { UI_I_WindowCollapsedData } from '~/components/atoms/window/lib/models/interfaces'
90
+ import {
91
+ minWidth,
92
+ minHeight,
93
+ headerHeight,
94
+ windowPadding,
95
+ } from '~/components/atoms/window/lib/config/config'
96
+
97
+ const props = withDefaults(
98
+ defineProps<{
99
+ top: number
100
+ left: number
101
+ width: number
102
+ height: number
103
+ title: string
104
+ loading?: boolean
105
+ }>(),
106
+ {
107
+ loading: false,
108
+ }
109
+ )
110
+ const emits = defineEmits<{
111
+ (event: 'hide'): void
112
+ }>()
113
+
114
+ const windowContent = ref<any>(null)
115
+ const { toggle } = useFullscreen(windowContent)
116
+
117
+ const headerEl = ref(null)
118
+ const isShowContentBlocker = ref<boolean>(false)
119
+
120
+ const leftLocal = ref<number>(props.left)
121
+ const topLocal = ref<number>(props.top - headerHeight)
122
+ const widthLocal = ref<number>(Math.max(minWidth, props.width))
123
+ const heightLocal = ref<number>(
124
+ Math.max(minHeight, props.height + headerHeight)
125
+ )
126
+
127
+ const collapseData = ref<UI_I_WindowCollapsedData>({
128
+ isCollapsed: false,
129
+ cashTop: -1,
130
+ cashLeft: -1,
131
+ cashWidth: -1,
132
+ cashHeight: -1,
133
+ })
134
+
135
+ // Используем vueuse для перетаскивания
136
+ useDraggable(headerEl, {
137
+ initialValue: { x: leftLocal.value, y: topLocal.value },
138
+ onMove({ x: newX, y: newY }) {
139
+ leftLocal.value = newX
140
+ topLocal.value = newY
141
+ },
142
+ onStart() {
143
+ isShowContentBlocker.value = true
144
+ if (!collapseData.value.isCollapsed) {
145
+ collapseData.value.cashTop = topLocal.value
146
+ collapseData.value.cashLeft = leftLocal.value
147
+ collapseData.value.cashWidth = widthLocal.value
148
+ collapseData.value.cashHeight = heightLocal.value
149
+ }
150
+ },
151
+ onEnd() {
152
+ isShowContentBlocker.value = false
153
+ fixPosition()
154
+ },
155
+ })
156
+
157
+ const fixSize = (): void => {
158
+ const globalWindowWidth = window.innerWidth
159
+ const globalWindowHeight = window.innerHeight
160
+
161
+ widthLocal.value = Math.min(
162
+ globalWindowWidth - windowPadding * 2,
163
+ widthLocal.value
164
+ )
165
+ heightLocal.value = Math.min(
166
+ globalWindowHeight - windowPadding * 2,
167
+ heightLocal.value
168
+ )
169
+ }
170
+ const fixPosition = (): void => {
171
+ const globalWindowWidth = window.innerWidth
172
+ const globalWindowHeight = window.innerHeight
173
+ let newX = leftLocal.value
174
+ let newY = topLocal.value
175
+
176
+ if (leftLocal.value + widthLocal.value > globalWindowWidth - windowPadding) {
177
+ newX = globalWindowWidth - widthLocal.value - windowPadding
178
+ } else if (leftLocal.value < windowPadding) {
179
+ newX = windowPadding
180
+ }
181
+
182
+ if (topLocal.value + heightLocal.value / 2 > globalWindowHeight) {
183
+ newY = globalWindowHeight - headerHeight
184
+ collapseData.value.isCollapsed = true
185
+ } else if (
186
+ topLocal.value + heightLocal.value >
187
+ globalWindowHeight - windowPadding
188
+ ) {
189
+ newY = globalWindowHeight - heightLocal.value - windowPadding
190
+ collapseData.value.isCollapsed = false
191
+ } else if (topLocal.value < windowPadding) {
192
+ newY = windowPadding
193
+ collapseData.value.isCollapsed = false
194
+ } else {
195
+ collapseData.value.isCollapsed = false
196
+ }
197
+
198
+ smoothMove(newX, newY)
199
+ }
200
+ const smoothMove = (newX: number, newY: number, duration = 100): void => {
201
+ const startX = leftLocal.value
202
+ const startY = topLocal.value
203
+
204
+ // Время начала анимации
205
+ const startTime = performance.now()
206
+
207
+ // Функция анимации
208
+ const animate = (currentTime: number): void => {
209
+ // Прошедшее время с начала анимации
210
+ const elapsedTime = currentTime - startTime
211
+
212
+ // Прогресс анимации (от 0 до 1)
213
+ const progress = Math.min(elapsedTime / duration, 1)
214
+
215
+ // Вычисляем новые координаты с помощью линейной интерполяции
216
+ leftLocal.value = startX + (newX - startX) * progress
217
+ topLocal.value = startY + (newY - startY) * progress
218
+
219
+ // Если анимация не завершена, продолжаем
220
+ if (progress < 1) {
221
+ requestAnimationFrame(animate)
222
+ }
223
+ }
224
+
225
+ // Запускаем анимацию
226
+ requestAnimationFrame(animate)
227
+ }
228
+
229
+ const onCollapse = (): void => {
230
+ collapseData.value.isCollapsed = !collapseData.value.isCollapsed
231
+
232
+ if (collapseData.value.isCollapsed) {
233
+ collapseData.value.cashTop = topLocal.value
234
+ collapseData.value.cashLeft = leftLocal.value
235
+ collapseData.value.cashWidth = widthLocal.value
236
+ collapseData.value.cashHeight = heightLocal.value
237
+
238
+ const globalWindowWidth = window.innerWidth
239
+ const globalWindowHeight = window.innerHeight
240
+
241
+ widthLocal.value = minWidth
242
+ // heightLocal.value = minHeight
243
+ leftLocal.value = globalWindowWidth - widthLocal.value - windowPadding
244
+ topLocal.value = globalWindowHeight - headerHeight
245
+ fixPosition()
246
+ } else {
247
+ leftLocal.value = collapseData.value.cashLeft
248
+ topLocal.value = collapseData.value.cashTop
249
+ widthLocal.value = collapseData.value.cashWidth
250
+ heightLocal.value = collapseData.value.cashHeight
251
+ fixPosition()
252
+ }
253
+ }
254
+
255
+ // Функция для ресайза
256
+ const startResize = (e: any, direction: any): void => {
257
+ e.preventDefault()
258
+
259
+ const startX = e.clientX
260
+ const startY = e.clientY
261
+ const startWidth = widthLocal.value
262
+ const startHeight = heightLocal.value
263
+ const startLeft = leftLocal.value
264
+ const startTop = topLocal.value
265
+
266
+ const onMouseMove = (e: any): void => {
267
+ const deltaX = e.clientX - startX
268
+ const deltaY = e.clientY - startY
269
+
270
+ if (direction.includes('right')) {
271
+ widthLocal.value = Math.max(minWidth, startWidth + deltaX)
272
+ }
273
+ if (direction.includes('bottom')) {
274
+ heightLocal.value = Math.max(minHeight, startHeight + deltaY)
275
+ }
276
+ if (direction.includes('left')) {
277
+ const newWidth = Math.max(minWidth, startWidth - deltaX)
278
+ if (newWidth !== widthLocal.value) {
279
+ leftLocal.value = startLeft + deltaX
280
+ widthLocal.value = newWidth
281
+ }
282
+ }
283
+ if (direction.includes('top')) {
284
+ const newHeight = Math.max(minHeight, startHeight - deltaY)
285
+ if (newHeight !== heightLocal.value) {
286
+ topLocal.value = startTop + deltaY
287
+ heightLocal.value = newHeight
288
+ }
289
+ }
290
+ fixSize()
291
+ }
292
+
293
+ const onMouseUp = (): void => {
294
+ document.removeEventListener('mousemove', onMouseMove)
295
+ document.removeEventListener('mouseup', onMouseUp)
296
+ isShowContentBlocker.value = false
297
+ fixPosition()
298
+ }
299
+
300
+ document.addEventListener('mousemove', onMouseMove)
301
+ document.addEventListener('mouseup', onMouseUp)
302
+ isShowContentBlocker.value = true
303
+ }
304
+
305
+ let resizeTimer: any = null
306
+ const globalWindowResize = (): void => {
307
+ clearTimeout(resizeTimer)
308
+
309
+ resizeTimer = setTimeout(() => {
310
+ fixSize()
311
+ fixPosition()
312
+ }, 250)
313
+ }
314
+ onMounted(() => {
315
+ window.addEventListener('resize', globalWindowResize)
316
+ fixSize()
317
+ fixPosition()
318
+ })
319
+ onUnmounted(() => {
320
+ window.removeEventListener('resize', globalWindowResize)
321
+ })
322
+
323
+ const onHide = (): void => {
324
+ emits('hide')
325
+ }
326
+ </script>
327
+
328
+ <style lang="scss">
329
+ .window-container {
330
+ position: absolute;
331
+ border-radius: 6px;
332
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
333
+ overflow: hidden;
334
+ background-color: #fff;
335
+ display: flex;
336
+ flex-direction: column;
337
+ //min-width: 300px;
338
+ //min-height: 200px;
339
+ z-index: var(--z-fixed);
340
+
341
+ &.loading {
342
+ opacity: 0.5;
343
+ }
344
+
345
+ .window-header {
346
+ background-color: #314351;
347
+ color: white;
348
+ padding: 6px 12px;
349
+ cursor: move;
350
+ user-select: none;
351
+ display: flex;
352
+ justify-content: space-between;
353
+ align-items: center;
354
+
355
+ .window-title {
356
+ font-size: 13px;
357
+ }
358
+
359
+ .window-btn {
360
+ background: none;
361
+ border: none;
362
+ color: #e4e4e4;
363
+ cursor: pointer;
364
+ width: 20px;
365
+ height: 20px;
366
+ display: flex;
367
+ justify-content: center;
368
+ align-items: center;
369
+
370
+ &:hover {
371
+ color: #ffffff;
372
+ }
373
+ }
374
+ }
375
+
376
+ .window-content {
377
+ position: relative;
378
+ flex-grow: 1;
379
+
380
+ .content-blocker {
381
+ position: absolute;
382
+ top: 0;
383
+ left: 0;
384
+ width: 100%;
385
+ height: 100%;
386
+ z-index: 1;
387
+ }
388
+ }
389
+
390
+ .resize-handle {
391
+ position: absolute;
392
+ background: transparent;
393
+ z-index: 10;
394
+
395
+ &.resize-top {
396
+ top: -3px;
397
+ left: 0;
398
+ right: 0;
399
+ height: 6px;
400
+ cursor: n-resize;
401
+ }
402
+
403
+ &.resize-right {
404
+ top: 0;
405
+ right: -3px;
406
+ bottom: 0;
407
+ width: 6px;
408
+ cursor: e-resize;
409
+ }
410
+
411
+ &.resize-bottom {
412
+ bottom: -3px;
413
+ left: 0;
414
+ right: 0;
415
+ height: 6px;
416
+ cursor: s-resize;
417
+ }
418
+
419
+ &.resize-left {
420
+ top: 0;
421
+ left: -3px;
422
+ bottom: 0;
423
+ width: 6px;
424
+ cursor: w-resize;
425
+ }
426
+
427
+ &.resize-top-left {
428
+ top: -6px;
429
+ left: -6px;
430
+ width: 12px;
431
+ height: 12px;
432
+ cursor: nw-resize;
433
+ }
434
+
435
+ &.resize-top-right {
436
+ top: -6px;
437
+ right: -6px;
438
+ width: 12px;
439
+ height: 12px;
440
+ cursor: ne-resize;
441
+ }
442
+
443
+ &.resize-bottom-left {
444
+ bottom: -6px;
445
+ left: -6px;
446
+ width: 12px;
447
+ height: 12px;
448
+ cursor: sw-resize;
449
+ }
450
+
451
+ &.resize-bottom-right {
452
+ bottom: -6px;
453
+ right: -6px;
454
+ width: 12px;
455
+ height: 12px;
456
+ cursor: se-resize;
457
+ }
458
+ }
459
+ }
460
+ </style>