@cloudron/pankow 4.4.12 → 4.4.13
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/FormGroup.vue
CHANGED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
|
|
3
|
+
defineProps({
|
|
4
|
+
orientation: {
|
|
5
|
+
type: String,
|
|
6
|
+
default: 'horizontal'
|
|
7
|
+
},
|
|
8
|
+
opaque: {
|
|
9
|
+
type: Boolean,
|
|
10
|
+
default: false
|
|
11
|
+
},
|
|
12
|
+
dragging: {
|
|
13
|
+
type: Boolean,
|
|
14
|
+
default: false
|
|
15
|
+
},
|
|
16
|
+
contrast: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: 'auto'
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<div
|
|
26
|
+
class="pankow-resize-handle"
|
|
27
|
+
:class="{
|
|
28
|
+
'pankow-resize-handle-vertical': orientation === 'vertical',
|
|
29
|
+
'pankow-resize-handle-opaque': opaque,
|
|
30
|
+
'pankow-resize-handle-dragging': dragging,
|
|
31
|
+
'pankow-resize-handle-contrast-light': contrast === 'light',
|
|
32
|
+
'pankow-resize-handle-contrast-dark': contrast === 'dark'
|
|
33
|
+
}"
|
|
34
|
+
>
|
|
35
|
+
<div class="pankow-resize-handle-grip"><span></span><span></span></div>
|
|
36
|
+
</div>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<style>
|
|
40
|
+
|
|
41
|
+
.pankow-resize-handle {
|
|
42
|
+
background: transparent;
|
|
43
|
+
position: relative;
|
|
44
|
+
flex-shrink: 0;
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.pankow-resize-handle:not(.pankow-resize-handle-vertical) {
|
|
51
|
+
width: 6px;
|
|
52
|
+
cursor: col-resize;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.pankow-resize-handle-vertical {
|
|
56
|
+
height: 6px;
|
|
57
|
+
cursor: row-resize;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.pankow-resize-handle-opaque {
|
|
61
|
+
background: var(--pankow-color-background);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.pankow-resize-handle:hover,
|
|
65
|
+
.pankow-resize-handle-dragging {
|
|
66
|
+
background: var(--pankow-input-border-color);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.pankow-resize-handle-grip {
|
|
70
|
+
position: absolute;
|
|
71
|
+
top: 50%;
|
|
72
|
+
left: 50%;
|
|
73
|
+
transform: translate(-50%, -50%);
|
|
74
|
+
display: flex;
|
|
75
|
+
gap: 2px;
|
|
76
|
+
opacity: 0;
|
|
77
|
+
transition: opacity 0.15s;
|
|
78
|
+
pointer-events: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.pankow-resize-handle:not(.pankow-resize-handle-vertical) .pankow-resize-handle-grip {
|
|
82
|
+
flex-direction: column;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.pankow-resize-handle-vertical .pankow-resize-handle-grip {
|
|
86
|
+
flex-direction: row;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.pankow-resize-handle:hover .pankow-resize-handle-grip,
|
|
90
|
+
.pankow-resize-handle-dragging .pankow-resize-handle-grip {
|
|
91
|
+
opacity: 0.5;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.pankow-resize-handle-grip span {
|
|
95
|
+
display: block;
|
|
96
|
+
border-radius: 1px;
|
|
97
|
+
background: currentColor;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.pankow-resize-handle-contrast-light .pankow-resize-handle-grip span {
|
|
101
|
+
background: var(--pankow-text-color-white);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.pankow-resize-handle-contrast-dark .pankow-resize-handle-grip span {
|
|
105
|
+
background: var(--pankow-color-dark);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.pankow-resize-handle:not(.pankow-resize-handle-vertical) .pankow-resize-handle-grip span {
|
|
109
|
+
width: 2px;
|
|
110
|
+
height: 16px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.pankow-resize-handle-vertical .pankow-resize-handle-grip span {
|
|
114
|
+
width: 16px;
|
|
115
|
+
height: 2px;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
</style>
|
package/components/SideBar.vue
CHANGED
|
@@ -2,18 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
import { ref, useTemplateRef, onMounted, onUnmounted, nextTick } from 'vue';
|
|
4
4
|
import { onPan } from '../gestures.js';
|
|
5
|
+
import ResizeHandle from './ResizeHandle.vue';
|
|
5
6
|
|
|
6
|
-
defineProps({
|
|
7
|
+
const props = defineProps({
|
|
7
8
|
showOpenAction: {
|
|
8
9
|
type: Boolean,
|
|
9
10
|
default: true
|
|
10
11
|
},
|
|
12
|
+
resizable: {
|
|
13
|
+
type: Boolean,
|
|
14
|
+
default: false
|
|
15
|
+
},
|
|
16
|
+
storageKey: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: 'pankow-sidebar-width'
|
|
19
|
+
},
|
|
11
20
|
});
|
|
12
21
|
|
|
22
|
+
const container = useTemplateRef('container');
|
|
13
23
|
const sideBar = useTemplateRef('sideBar');
|
|
14
24
|
const backDrop = useTemplateRef('backDrop');
|
|
15
25
|
const isVisible = ref(false);
|
|
16
26
|
const dragging = ref(false);
|
|
27
|
+
const resizing = ref(false);
|
|
28
|
+
|
|
29
|
+
const SIDEBAR_MIN_WIDTH = 200;
|
|
30
|
+
const SIDEBAR_MAX_WIDTH = 600;
|
|
31
|
+
let resizeStartX = 0;
|
|
32
|
+
let resizeStartWidth = 0;
|
|
17
33
|
|
|
18
34
|
function open() {
|
|
19
35
|
isVisible.value = true;
|
|
@@ -107,6 +123,62 @@ function dragCancel() {
|
|
|
107
123
|
settle(false);
|
|
108
124
|
}
|
|
109
125
|
|
|
126
|
+
function resizeStart(event) {
|
|
127
|
+
if (!props.resizable) return;
|
|
128
|
+
resizing.value = true;
|
|
129
|
+
resizeStartX = event.clientX ?? event.touches?.[0]?.clientX ?? 0;
|
|
130
|
+
resizeStartWidth = container.value ? container.value.offsetWidth : 0;
|
|
131
|
+
document.body.style.cursor = 'col-resize';
|
|
132
|
+
document.body.style.userSelect = 'none';
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function resizeMove(event) {
|
|
137
|
+
if (!resizing.value || !container.value) return;
|
|
138
|
+
const x = event.clientX ?? event.touches?.[0]?.clientX ?? 0;
|
|
139
|
+
const width = Math.max(SIDEBAR_MIN_WIDTH, Math.min(SIDEBAR_MAX_WIDTH, resizeStartWidth + (x - resizeStartX)));
|
|
140
|
+
applyWidth(width);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function resizeEnd() {
|
|
144
|
+
if (!resizing.value) return;
|
|
145
|
+
resizing.value = false;
|
|
146
|
+
document.body.style.cursor = '';
|
|
147
|
+
document.body.style.userSelect = '';
|
|
148
|
+
saveWidth();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function applyWidth(width) {
|
|
152
|
+
if (!container.value) return;
|
|
153
|
+
container.value.style.width = `${width}px`;
|
|
154
|
+
container.value.style.minWidth = `${width}px`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function saveWidth() {
|
|
158
|
+
if (!props.resizable || !container.value || typeof window === 'undefined') return;
|
|
159
|
+
try {
|
|
160
|
+
window.localStorage.setItem(props.storageKey, String(container.value.offsetWidth));
|
|
161
|
+
} catch (e) { /* ignore */ }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function restoreWidth() {
|
|
165
|
+
if (!props.resizable || typeof window === 'undefined') return;
|
|
166
|
+
try {
|
|
167
|
+
const stored = window.localStorage.getItem(props.storageKey);
|
|
168
|
+
if (!stored) return;
|
|
169
|
+
const width = parseInt(stored, 10);
|
|
170
|
+
if (Number.isNaN(width)) return;
|
|
171
|
+
applyWidth(Math.max(SIDEBAR_MIN_WIDTH, Math.min(SIDEBAR_MAX_WIDTH, width)));
|
|
172
|
+
} catch (e) { /* ignore */ }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function clearResizeWidth() {
|
|
176
|
+
if (container.value) {
|
|
177
|
+
container.value.style.width = '';
|
|
178
|
+
container.value.style.minWidth = '';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
110
182
|
let removePans = [];
|
|
111
183
|
let settleTimer = null;
|
|
112
184
|
let settleOnEnd = null;
|
|
@@ -135,17 +207,30 @@ function teardown() {
|
|
|
135
207
|
}
|
|
136
208
|
|
|
137
209
|
function onMediaChange() {
|
|
138
|
-
if (media && media.matches)
|
|
139
|
-
|
|
210
|
+
if (media && media.matches) {
|
|
211
|
+
setup();
|
|
212
|
+
clearResizeWidth();
|
|
213
|
+
} else {
|
|
214
|
+
teardown();
|
|
215
|
+
}
|
|
140
216
|
}
|
|
141
217
|
|
|
142
218
|
onMounted(() => {
|
|
143
219
|
setup();
|
|
220
|
+
restoreWidth();
|
|
221
|
+
document.addEventListener('mousemove', resizeMove);
|
|
222
|
+
document.addEventListener('mouseup', resizeEnd);
|
|
223
|
+
document.addEventListener('touchmove', resizeMove, { passive: false });
|
|
224
|
+
document.addEventListener('touchend', resizeEnd);
|
|
144
225
|
media && media.addEventListener('change', onMediaChange);
|
|
145
226
|
});
|
|
146
227
|
|
|
147
228
|
onUnmounted(() => {
|
|
148
229
|
media && media.removeEventListener('change', onMediaChange);
|
|
230
|
+
document.removeEventListener('mousemove', resizeMove);
|
|
231
|
+
document.removeEventListener('mouseup', resizeEnd);
|
|
232
|
+
document.removeEventListener('touchmove', resizeMove);
|
|
233
|
+
document.removeEventListener('touchend', resizeEnd);
|
|
149
234
|
teardown();
|
|
150
235
|
});
|
|
151
236
|
|
|
@@ -154,7 +239,7 @@ defineExpose({ open, close });
|
|
|
154
239
|
</script>
|
|
155
240
|
|
|
156
241
|
<template>
|
|
157
|
-
<div class="pankow-sidebar-container" :class="{ 'pankow-sidebar-open': isVisible, 'pankow-sidebar-dragging': dragging }">
|
|
242
|
+
<div class="pankow-sidebar-container" ref="container" :class="{ 'pankow-sidebar-open': isVisible, 'pankow-sidebar-dragging': dragging, 'pankow-sidebar-resizing': resizing }">
|
|
158
243
|
<div class="pankow-sidebar-backdrop" ref="backDrop" @click="onBackdropClick"></div>
|
|
159
244
|
<Transition name="pankow-scale">
|
|
160
245
|
<div class="pankow-sidebar-close-action" v-if="isVisible" tabindex="0" role="button" aria-label="Close sidebar" @click="close()" @keydown.enter="close()" @keydown.space.prevent="close()"><i class="fa-solid fa-xmark"></i></div>
|
|
@@ -165,6 +250,15 @@ defineExpose({ open, close });
|
|
|
165
250
|
<slot></slot>
|
|
166
251
|
</div>
|
|
167
252
|
</div>
|
|
253
|
+
<ResizeHandle
|
|
254
|
+
v-if="resizable"
|
|
255
|
+
class="pankow-sidebar-resize-handle"
|
|
256
|
+
orientation="horizontal"
|
|
257
|
+
contrast="light"
|
|
258
|
+
:dragging="resizing"
|
|
259
|
+
@mousedown="resizeStart"
|
|
260
|
+
@touchstart.prevent="resizeStart"
|
|
261
|
+
/>
|
|
168
262
|
</div>
|
|
169
263
|
</template>
|
|
170
264
|
|
|
@@ -173,7 +267,20 @@ defineExpose({ open, close });
|
|
|
173
267
|
.pankow-sidebar-container {
|
|
174
268
|
display: block;
|
|
175
269
|
height: 100%;
|
|
176
|
-
min-width:
|
|
270
|
+
min-width: 280px;
|
|
271
|
+
position: relative;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.pankow-sidebar-resize-handle {
|
|
275
|
+
position: absolute;
|
|
276
|
+
top: 0;
|
|
277
|
+
right: 0;
|
|
278
|
+
bottom: 0;
|
|
279
|
+
z-index: 1;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.pankow-sidebar-resizing {
|
|
283
|
+
user-select: none;
|
|
177
284
|
}
|
|
178
285
|
|
|
179
286
|
.pankow-sidebar {
|
|
@@ -278,6 +385,10 @@ defineExpose({ open, close });
|
|
|
278
385
|
.pankow-sidebar-close-action {
|
|
279
386
|
display: block;
|
|
280
387
|
}
|
|
388
|
+
|
|
389
|
+
.pankow-sidebar-resize-handle {
|
|
390
|
+
display: none;
|
|
391
|
+
}
|
|
281
392
|
}
|
|
282
393
|
|
|
283
394
|
</style>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref, computed, watch, onMounted, onUnmounted, useTemplateRef } from 'vue';
|
|
3
|
+
import ResizeHandle from './ResizeHandle.vue';
|
|
3
4
|
|
|
4
5
|
const props = defineProps({
|
|
5
6
|
orientation: {
|
|
@@ -142,20 +143,19 @@ const firstStyle = computed(() => {
|
|
|
142
143
|
class="pankow-split-layout"
|
|
143
144
|
:class="{
|
|
144
145
|
'pankow-split-layout-dragging': isDragging,
|
|
145
|
-
'pankow-split-layout-vertical': !isHorizontal
|
|
146
|
-
'pankow-split-layout-divider-opaque': opaque
|
|
146
|
+
'pankow-split-layout-vertical': !isHorizontal
|
|
147
147
|
}"
|
|
148
148
|
>
|
|
149
149
|
<div class="pankow-split-layout-first" :style="firstStyle">
|
|
150
150
|
<slot name="left" />
|
|
151
151
|
</div>
|
|
152
|
-
<
|
|
153
|
-
|
|
152
|
+
<ResizeHandle
|
|
153
|
+
:orientation="orientation"
|
|
154
|
+
:opaque="opaque"
|
|
155
|
+
:dragging="isDragging"
|
|
154
156
|
@mousedown="startDrag"
|
|
155
157
|
@touchstart.prevent="startDrag"
|
|
156
|
-
|
|
157
|
-
<div class="pankow-split-layout-handle"><span></span><span></span></div>
|
|
158
|
-
</div>
|
|
158
|
+
/>
|
|
159
159
|
<div class="pankow-split-layout-second">
|
|
160
160
|
<slot name="right" />
|
|
161
161
|
</div>
|
|
@@ -186,75 +186,6 @@ const firstStyle = computed(() => {
|
|
|
186
186
|
min-width: 0;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
.pankow-split-layout-divider {
|
|
190
|
-
background: transparent;
|
|
191
|
-
position: relative;
|
|
192
|
-
flex-shrink: 0;
|
|
193
|
-
display: flex;
|
|
194
|
-
align-items: center;
|
|
195
|
-
justify-content: center;
|
|
196
|
-
}
|
|
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
|
-
|
|
212
|
-
.pankow-split-layout-divider:hover,
|
|
213
|
-
.pankow-split-layout-dragging .pankow-split-layout-divider {
|
|
214
|
-
background: var(--pankow-input-border-color);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
.pankow-split-layout-handle {
|
|
218
|
-
position: absolute;
|
|
219
|
-
top: 50%;
|
|
220
|
-
left: 50%;
|
|
221
|
-
transform: translate(-50%, -50%);
|
|
222
|
-
display: flex;
|
|
223
|
-
gap: 2px;
|
|
224
|
-
opacity: 0;
|
|
225
|
-
transition: opacity 0.15s;
|
|
226
|
-
pointer-events: none;
|
|
227
|
-
}
|
|
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
|
-
|
|
237
|
-
.pankow-split-layout-divider:hover .pankow-split-layout-handle,
|
|
238
|
-
.pankow-split-layout-dragging .pankow-split-layout-handle {
|
|
239
|
-
opacity: 0.5;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.pankow-split-layout-handle span {
|
|
243
|
-
display: block;
|
|
244
|
-
border-radius: 1px;
|
|
245
|
-
background: var(--pankow-color-text);
|
|
246
|
-
}
|
|
247
|
-
|
|
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
189
|
.pankow-split-layout-second {
|
|
259
190
|
flex: 1;
|
|
260
191
|
min-width: 0;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudron/pankow",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "4.4.
|
|
4
|
+
"version": "4.4.13",
|
|
5
5
|
"description": "Vue 3 UI component library for Cloudron apps",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "types/index.d.ts",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@fontsource/inter": "^5.3.0",
|
|
41
41
|
"@fortawesome/fontawesome-free": "^7.3.1",
|
|
42
|
-
"filesize": "^11.0.
|
|
42
|
+
"filesize": "^11.0.23",
|
|
43
43
|
"monaco-editor": "^0.56.0",
|
|
44
44
|
"online-3d-viewer": "^0.18.0"
|
|
45
45
|
},
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"vite": "^8.2.2",
|
|
56
56
|
"vite-ssg": "^28.3.0",
|
|
57
57
|
"vue": "^3.5.42",
|
|
58
|
-
"vue-router": "^5.
|
|
58
|
+
"vue-router": "^5.3.1"
|
|
59
59
|
},
|
|
60
60
|
"allowScripts": {
|
|
61
61
|
"core-js": false
|