@cloudron/pankow 4.4.1 → 4.4.2
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.
- package/components/SplitLayout.vue +146 -34
- package/package.json +1 -1
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
import { ref, computed, watch, onMounted, onUnmounted, useTemplateRef } from 'vue';
|
|
3
3
|
|
|
4
4
|
const props = defineProps({
|
|
5
|
+
orientation: {
|
|
6
|
+
type: String,
|
|
7
|
+
default: 'horizontal'
|
|
8
|
+
},
|
|
9
|
+
// horizontal mode props
|
|
5
10
|
leftWidth: {
|
|
6
11
|
type: Number,
|
|
7
12
|
default: 50
|
|
@@ -13,40 +18,88 @@ const props = defineProps({
|
|
|
13
18
|
minRightWidth: {
|
|
14
19
|
type: Number,
|
|
15
20
|
default: 20
|
|
21
|
+
},
|
|
22
|
+
// vertical mode props
|
|
23
|
+
topHeight: {
|
|
24
|
+
type: Number,
|
|
25
|
+
default: 50
|
|
26
|
+
},
|
|
27
|
+
minTopHeight: {
|
|
28
|
+
type: Number,
|
|
29
|
+
default: 20
|
|
30
|
+
},
|
|
31
|
+
minBottomHeight: {
|
|
32
|
+
type: Number,
|
|
33
|
+
default: 20
|
|
34
|
+
},
|
|
35
|
+
opaque: {
|
|
36
|
+
type: Boolean,
|
|
37
|
+
default: false
|
|
16
38
|
}
|
|
17
39
|
});
|
|
18
40
|
|
|
19
|
-
const emit = defineEmits(['update:leftWidth']);
|
|
41
|
+
const emit = defineEmits(['update:leftWidth', 'update:topHeight']);
|
|
42
|
+
|
|
43
|
+
const isHorizontal = computed(() => props.orientation === 'horizontal');
|
|
20
44
|
|
|
21
45
|
const containerRef = useTemplateRef('container');
|
|
22
46
|
const isDragging = ref(false);
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
47
|
+
const dragStartCoord = ref(0);
|
|
48
|
+
const dragStartSize = ref(0);
|
|
49
|
+
|
|
50
|
+
const currentFirstSize = ref(
|
|
51
|
+
isHorizontal.value ? props.leftWidth : props.topHeight
|
|
52
|
+
);
|
|
26
53
|
|
|
27
54
|
watch(() => props.leftWidth, (val) => {
|
|
55
|
+
if (!isDragging.value && isHorizontal.value) {
|
|
56
|
+
currentFirstSize.value = val;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
watch(() => props.topHeight, (val) => {
|
|
61
|
+
if (!isDragging.value && !isHorizontal.value) {
|
|
62
|
+
currentFirstSize.value = val;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
watch(() => props.orientation, () => {
|
|
28
67
|
if (!isDragging.value) {
|
|
29
|
-
|
|
68
|
+
currentFirstSize.value = isHorizontal.value ? props.leftWidth : props.topHeight;
|
|
30
69
|
}
|
|
31
70
|
});
|
|
32
71
|
|
|
72
|
+
const minFirst = computed(() =>
|
|
73
|
+
isHorizontal.value ? props.minLeftWidth : props.minTopHeight
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const minSecond = computed(() =>
|
|
77
|
+
isHorizontal.value ? props.minRightWidth : props.minBottomHeight
|
|
78
|
+
);
|
|
79
|
+
|
|
33
80
|
function startDrag(e) {
|
|
34
81
|
isDragging.value = true;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
82
|
+
dragStartCoord.value = isHorizontal.value
|
|
83
|
+
? (e.clientX ?? e.touches?.[0]?.clientX ?? 0)
|
|
84
|
+
: (e.clientY ?? e.touches?.[0]?.clientY ?? 0);
|
|
85
|
+
dragStartSize.value = currentFirstSize.value;
|
|
86
|
+
document.body.style.cursor = isHorizontal.value ? 'col-resize' : 'row-resize';
|
|
38
87
|
document.body.style.userSelect = 'none';
|
|
39
88
|
e.preventDefault();
|
|
40
89
|
}
|
|
41
90
|
|
|
42
91
|
function onDrag(e) {
|
|
43
92
|
if (!isDragging.value || !containerRef.value) return;
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
93
|
+
const coord = isHorizontal.value
|
|
94
|
+
? (e.clientX ?? e.touches?.[0]?.clientX ?? 0)
|
|
95
|
+
: (e.clientY ?? e.touches?.[0]?.clientY ?? 0);
|
|
96
|
+
const containerSize = isHorizontal.value
|
|
97
|
+
? containerRef.value.getBoundingClientRect().width
|
|
98
|
+
: containerRef.value.getBoundingClientRect().height;
|
|
99
|
+
if (containerSize === 0) return;
|
|
100
|
+
const delta = ((coord - dragStartCoord.value) / containerSize) * 100;
|
|
101
|
+
const newSize = dragStartSize.value + delta;
|
|
102
|
+
currentFirstSize.value = Math.max(minFirst.value, Math.min(100 - minSecond.value, newSize));
|
|
50
103
|
}
|
|
51
104
|
|
|
52
105
|
function stopDrag() {
|
|
@@ -54,7 +107,11 @@ function stopDrag() {
|
|
|
54
107
|
isDragging.value = false;
|
|
55
108
|
document.body.style.cursor = '';
|
|
56
109
|
document.body.style.userSelect = '';
|
|
57
|
-
|
|
110
|
+
if (isHorizontal.value) {
|
|
111
|
+
emit('update:leftWidth', Math.round(currentFirstSize.value));
|
|
112
|
+
} else {
|
|
113
|
+
emit('update:topHeight', Math.round(currentFirstSize.value));
|
|
114
|
+
}
|
|
58
115
|
}
|
|
59
116
|
|
|
60
117
|
onMounted(() => {
|
|
@@ -71,21 +128,35 @@ onUnmounted(() => {
|
|
|
71
128
|
document.removeEventListener('touchend', stopDrag);
|
|
72
129
|
});
|
|
73
130
|
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
131
|
+
const firstStyle = computed(() => {
|
|
132
|
+
const size = currentFirstSize.value;
|
|
133
|
+
return isHorizontal.value
|
|
134
|
+
? { flex: `0 0 ${size}%`, maxWidth: `${size}%` }
|
|
135
|
+
: { flex: `0 0 ${size}%`, maxHeight: `${size}%` };
|
|
136
|
+
});
|
|
78
137
|
</script>
|
|
79
138
|
|
|
80
139
|
<template>
|
|
81
|
-
<div
|
|
82
|
-
|
|
140
|
+
<div
|
|
141
|
+
ref="container"
|
|
142
|
+
class="pankow-split-layout"
|
|
143
|
+
:class="{
|
|
144
|
+
'pankow-split-layout-dragging': isDragging,
|
|
145
|
+
'pankow-split-layout-vertical': !isHorizontal,
|
|
146
|
+
'pankow-split-layout-divider-opaque': opaque
|
|
147
|
+
}"
|
|
148
|
+
>
|
|
149
|
+
<div class="pankow-split-layout-first" :style="firstStyle">
|
|
83
150
|
<slot name="left" />
|
|
84
151
|
</div>
|
|
85
|
-
<div
|
|
152
|
+
<div
|
|
153
|
+
class="pankow-split-layout-divider"
|
|
154
|
+
@mousedown="startDrag"
|
|
155
|
+
@touchstart.prevent="startDrag"
|
|
156
|
+
>
|
|
86
157
|
<div class="pankow-split-layout-handle"><span></span><span></span></div>
|
|
87
158
|
</div>
|
|
88
|
-
<div class="pankow-split-layout-
|
|
159
|
+
<div class="pankow-split-layout-second">
|
|
89
160
|
<slot name="right" />
|
|
90
161
|
</div>
|
|
91
162
|
</div>
|
|
@@ -100,15 +171,22 @@ const leftStyle = computed(() => ({
|
|
|
100
171
|
overflow: hidden;
|
|
101
172
|
}
|
|
102
173
|
|
|
103
|
-
.pankow-split-layout-
|
|
104
|
-
|
|
174
|
+
.pankow-split-layout-vertical {
|
|
175
|
+
flex-direction: column;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.pankow-split-layout-first {
|
|
105
179
|
min-width: 0;
|
|
106
180
|
overflow: hidden;
|
|
107
181
|
}
|
|
108
182
|
|
|
183
|
+
.pankow-split-layout-vertical .pankow-split-layout-first {
|
|
184
|
+
height: auto;
|
|
185
|
+
min-height: 0;
|
|
186
|
+
min-width: 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
109
189
|
.pankow-split-layout-divider {
|
|
110
|
-
width: 6px;
|
|
111
|
-
cursor: col-resize;
|
|
112
190
|
background: transparent;
|
|
113
191
|
position: relative;
|
|
114
192
|
flex-shrink: 0;
|
|
@@ -117,6 +195,20 @@ const leftStyle = computed(() => ({
|
|
|
117
195
|
justify-content: center;
|
|
118
196
|
}
|
|
119
197
|
|
|
198
|
+
.pankow-split-layout:not(.pankow-split-layout-vertical) .pankow-split-layout-divider {
|
|
199
|
+
width: 6px;
|
|
200
|
+
cursor: col-resize;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.pankow-split-layout-vertical .pankow-split-layout-divider {
|
|
204
|
+
height: 6px;
|
|
205
|
+
cursor: row-resize;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.pankow-split-layout-divider-opaque .pankow-split-layout-divider {
|
|
209
|
+
background: var(--pankow-color-background);
|
|
210
|
+
}
|
|
211
|
+
|
|
120
212
|
.pankow-split-layout-divider:hover,
|
|
121
213
|
.pankow-split-layout-dragging .pankow-split-layout-divider {
|
|
122
214
|
background: var(--pankow-input-border-color);
|
|
@@ -128,13 +220,20 @@ const leftStyle = computed(() => ({
|
|
|
128
220
|
left: 50%;
|
|
129
221
|
transform: translate(-50%, -50%);
|
|
130
222
|
display: flex;
|
|
131
|
-
flex-direction: column;
|
|
132
223
|
gap: 2px;
|
|
133
224
|
opacity: 0;
|
|
134
225
|
transition: opacity 0.15s;
|
|
135
226
|
pointer-events: none;
|
|
136
227
|
}
|
|
137
228
|
|
|
229
|
+
.pankow-split-layout:not(.pankow-split-layout-vertical) .pankow-split-layout-handle {
|
|
230
|
+
flex-direction: column;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.pankow-split-layout-vertical .pankow-split-layout-handle {
|
|
234
|
+
flex-direction: row;
|
|
235
|
+
}
|
|
236
|
+
|
|
138
237
|
.pankow-split-layout-divider:hover .pankow-split-layout-handle,
|
|
139
238
|
.pankow-split-layout-dragging .pankow-split-layout-handle {
|
|
140
239
|
opacity: 0.5;
|
|
@@ -142,21 +241,34 @@ const leftStyle = computed(() => ({
|
|
|
142
241
|
|
|
143
242
|
.pankow-split-layout-handle span {
|
|
144
243
|
display: block;
|
|
145
|
-
width: 2px;
|
|
146
|
-
height: 16px;
|
|
147
244
|
border-radius: 1px;
|
|
148
245
|
background: var(--pankow-color-text);
|
|
149
246
|
}
|
|
150
247
|
|
|
151
|
-
.pankow-split-layout-
|
|
248
|
+
.pankow-split-layout:not(.pankow-split-layout-vertical) .pankow-split-layout-handle span {
|
|
249
|
+
width: 2px;
|
|
250
|
+
height: 16px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.pankow-split-layout-vertical .pankow-split-layout-handle span {
|
|
254
|
+
width: 16px;
|
|
255
|
+
height: 2px;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.pankow-split-layout-second {
|
|
152
259
|
flex: 1;
|
|
153
|
-
height: 100%;
|
|
154
260
|
min-width: 0;
|
|
155
261
|
overflow: hidden;
|
|
156
262
|
}
|
|
157
263
|
|
|
158
|
-
.pankow-split-layout-
|
|
159
|
-
|
|
264
|
+
.pankow-split-layout-vertical .pankow-split-layout-second {
|
|
265
|
+
height: auto;
|
|
266
|
+
min-height: 0;
|
|
267
|
+
min-width: 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.pankow-split-layout-dragging .pankow-split-layout-first,
|
|
271
|
+
.pankow-split-layout-dragging .pankow-split-layout-second {
|
|
160
272
|
pointer-events: none;
|
|
161
273
|
}
|
|
162
274
|
</style>
|