ketekny-ui-kit 1.0.117 → 1.0.118
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/package.json
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<main
|
|
2
|
+
<main
|
|
3
|
+
class="flex min-h-0 w-full max-w-none flex-1 flex-col overflow-hidden bg-slate-100"
|
|
4
|
+
@touchstart.passive="handleTouchStart"
|
|
5
|
+
@touchmove.passive="handleTouchMove"
|
|
6
|
+
@touchend="handleTouchEnd"
|
|
7
|
+
@touchcancel="resetTouchState"
|
|
8
|
+
>
|
|
3
9
|
<div
|
|
4
|
-
v-if="
|
|
10
|
+
v-if="showMobileOverlay"
|
|
5
11
|
class="fixed inset-0 z-20 bg-slate-950/40 backdrop-blur-[1px] lg:hidden"
|
|
12
|
+
:style="mobileOverlayStyle"
|
|
6
13
|
@click="toggleMobileSidebar"
|
|
7
14
|
/>
|
|
8
15
|
|
|
@@ -70,7 +77,7 @@
|
|
|
70
77
|
v-if="showSidebar"
|
|
71
78
|
class="min-h-0 shrink-0 overflow-y-auto bg-slate-100 px-4 sm:px-6 lg:ml-8 lg:pr-4 lg:pl-0"
|
|
72
79
|
:class="mobileSidebarClass"
|
|
73
|
-
:style="
|
|
80
|
+
:style="mobileSidebarStyle"
|
|
74
81
|
>
|
|
75
82
|
<slot name="sidebar" />
|
|
76
83
|
</aside>
|
|
@@ -88,6 +95,9 @@ import kButton from '../ui/kButton.vue'
|
|
|
88
95
|
|
|
89
96
|
const LG_VIEWPORT_QUERY = '(min-width: 1024px)'
|
|
90
97
|
const MAIN_MENU_TOGGLE_EVENT = 'ketekny:two-col-layout-mobile-menu'
|
|
98
|
+
const MOBILE_EDGE_SWIPE_THRESHOLD = 72
|
|
99
|
+
const MOBILE_SWIPE_OPEN_DISTANCE = 52
|
|
100
|
+
const MOBILE_SWIPE_VERTICAL_TOLERANCE = 48
|
|
91
101
|
|
|
92
102
|
export default {
|
|
93
103
|
name: 'PageTwoColShell',
|
|
@@ -119,6 +129,12 @@ export default {
|
|
|
119
129
|
isDesktopViewport: true,
|
|
120
130
|
mobileSidebarOpen: false,
|
|
121
131
|
viewportQuery: null,
|
|
132
|
+
touchGesture: {
|
|
133
|
+
startX: 0,
|
|
134
|
+
startY: 0,
|
|
135
|
+
currentX: 0,
|
|
136
|
+
trackingEdgeSwipe: false,
|
|
137
|
+
},
|
|
122
138
|
}
|
|
123
139
|
},
|
|
124
140
|
computed: {
|
|
@@ -143,10 +159,38 @@ export default {
|
|
|
143
159
|
},
|
|
144
160
|
mobileSidebarClass() {
|
|
145
161
|
if (this.isDesktopViewport) return ''
|
|
146
|
-
return 'fixed left-0 top-0 z-20 h-full max-w-[85vw] border-r border-slate-200 bg-slate-100 py-4 shadow-xl shadow-slate-900/20'
|
|
162
|
+
return 'fixed left-0 top-0 z-20 h-full max-w-[85vw] border-r border-slate-200 bg-slate-100 py-4 shadow-xl shadow-slate-900/20 transition-transform duration-200 ease-out'
|
|
163
|
+
},
|
|
164
|
+
dragOffset() {
|
|
165
|
+
if (!this.touchGesture.trackingEdgeSwipe) return 0
|
|
166
|
+
return Math.max(0, this.touchGesture.currentX - this.touchGesture.startX)
|
|
167
|
+
},
|
|
168
|
+
mobileSidebarStyle() {
|
|
169
|
+
const baseStyle = this.sidebarStyle
|
|
170
|
+
if (this.isDesktopViewport || this.mobileSidebarOpen || !this.touchGesture.trackingEdgeSwipe) {
|
|
171
|
+
return baseStyle
|
|
172
|
+
}
|
|
173
|
+
const widthValue = Number.parseFloat(this.sidebarWidth)
|
|
174
|
+
const effectiveWidth = Number.isFinite(widthValue) ? widthValue : 300
|
|
175
|
+
const clampedOffset = Math.min(this.dragOffset, effectiveWidth)
|
|
176
|
+
return {
|
|
177
|
+
...baseStyle,
|
|
178
|
+
transform: `translateX(${clampedOffset - effectiveWidth}px)`,
|
|
179
|
+
transition: 'none',
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
showMobileOverlay() {
|
|
183
|
+
return !this.isDesktopViewport && (this.mobileSidebarOpen || this.touchGesture.trackingEdgeSwipe)
|
|
184
|
+
},
|
|
185
|
+
mobileOverlayStyle() {
|
|
186
|
+
if (this.mobileSidebarOpen || !this.touchGesture.trackingEdgeSwipe) return null
|
|
187
|
+
const progress = Math.min(this.dragOffset / MOBILE_SWIPE_OPEN_DISTANCE, 1) * 0.4
|
|
188
|
+
return {
|
|
189
|
+
opacity: String(progress),
|
|
190
|
+
}
|
|
147
191
|
},
|
|
148
192
|
showSidebar() {
|
|
149
|
-
return this.isDesktopViewport || this.mobileSidebarOpen
|
|
193
|
+
return this.isDesktopViewport || this.mobileSidebarOpen || this.touchGesture.trackingEdgeSwipe
|
|
150
194
|
},
|
|
151
195
|
},
|
|
152
196
|
mounted() {
|
|
@@ -175,11 +219,55 @@ export default {
|
|
|
175
219
|
syncSidebarForViewport() {
|
|
176
220
|
if (!this.isDesktopViewport) {
|
|
177
221
|
this.mobileSidebarOpen = false
|
|
222
|
+
this.resetTouchState()
|
|
178
223
|
}
|
|
179
224
|
},
|
|
180
225
|
toggleMobileSidebar() {
|
|
181
226
|
if (this.isDesktopViewport) return
|
|
182
227
|
this.mobileSidebarOpen = !this.mobileSidebarOpen
|
|
228
|
+
this.resetTouchState()
|
|
229
|
+
},
|
|
230
|
+
handleTouchStart(event) {
|
|
231
|
+
if (this.isDesktopViewport || this.mobileSidebarOpen) {
|
|
232
|
+
this.resetTouchState()
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
const touch = event.touches?.[0]
|
|
236
|
+
if (!touch) return
|
|
237
|
+
this.touchGesture = {
|
|
238
|
+
startX: touch.clientX,
|
|
239
|
+
startY: touch.clientY,
|
|
240
|
+
currentX: touch.clientX,
|
|
241
|
+
trackingEdgeSwipe: touch.clientX <= MOBILE_EDGE_SWIPE_THRESHOLD,
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
handleTouchMove(event) {
|
|
245
|
+
if (!this.touchGesture.trackingEdgeSwipe) return
|
|
246
|
+
const touch = event.touches?.[0]
|
|
247
|
+
if (!touch) return
|
|
248
|
+
this.touchGesture.currentX = touch.clientX
|
|
249
|
+
if (Math.abs(touch.clientY - this.touchGesture.startY) > MOBILE_SWIPE_VERTICAL_TOLERANCE) {
|
|
250
|
+
this.resetTouchState()
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
handleTouchEnd() {
|
|
254
|
+
if (!this.touchGesture.trackingEdgeSwipe) {
|
|
255
|
+
this.resetTouchState()
|
|
256
|
+
return
|
|
257
|
+
}
|
|
258
|
+
const deltaX = this.touchGesture.currentX - this.touchGesture.startX
|
|
259
|
+
if (deltaX >= MOBILE_SWIPE_OPEN_DISTANCE) {
|
|
260
|
+
this.mobileSidebarOpen = true
|
|
261
|
+
}
|
|
262
|
+
this.resetTouchState()
|
|
263
|
+
},
|
|
264
|
+
resetTouchState() {
|
|
265
|
+
this.touchGesture = {
|
|
266
|
+
startX: 0,
|
|
267
|
+
startY: 0,
|
|
268
|
+
currentX: 0,
|
|
269
|
+
trackingEdgeSwipe: false,
|
|
270
|
+
}
|
|
183
271
|
},
|
|
184
272
|
openExternalUrl() {
|
|
185
273
|
const target = String(this.externalUrl || '').trim()
|