ketekny-ui-kit 1.0.116 → 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
|
|
|
@@ -58,9 +65,10 @@
|
|
|
58
65
|
:label="mobileSidebarOpen ? 'Hide sidebar' : 'Show sidebar'"
|
|
59
66
|
:icon="mobileSidebarOpen ? 'PanelLeftClose' : 'PanelLeftOpen'"
|
|
60
67
|
variant="soft"
|
|
68
|
+
size="large"
|
|
61
69
|
:icon-only="!mobileSidebarOpen"
|
|
62
70
|
:aria-label="mobileSidebarOpen ? null : 'Show sidebar'"
|
|
63
|
-
:class="mobileSidebarOpen ? '' : 'rounded-full shadow-lg shadow-slate-900/15'"
|
|
71
|
+
:class="mobileSidebarOpen ? '' : 'rounded-full text-slate-900 shadow-lg shadow-slate-900/15'"
|
|
64
72
|
@click="toggleMobileSidebar"
|
|
65
73
|
/>
|
|
66
74
|
</div>
|
|
@@ -69,7 +77,7 @@
|
|
|
69
77
|
v-if="showSidebar"
|
|
70
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"
|
|
71
79
|
:class="mobileSidebarClass"
|
|
72
|
-
:style="
|
|
80
|
+
:style="mobileSidebarStyle"
|
|
73
81
|
>
|
|
74
82
|
<slot name="sidebar" />
|
|
75
83
|
</aside>
|
|
@@ -87,6 +95,9 @@ import kButton from '../ui/kButton.vue'
|
|
|
87
95
|
|
|
88
96
|
const LG_VIEWPORT_QUERY = '(min-width: 1024px)'
|
|
89
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
|
|
90
101
|
|
|
91
102
|
export default {
|
|
92
103
|
name: 'PageTwoColShell',
|
|
@@ -118,6 +129,12 @@ export default {
|
|
|
118
129
|
isDesktopViewport: true,
|
|
119
130
|
mobileSidebarOpen: false,
|
|
120
131
|
viewportQuery: null,
|
|
132
|
+
touchGesture: {
|
|
133
|
+
startX: 0,
|
|
134
|
+
startY: 0,
|
|
135
|
+
currentX: 0,
|
|
136
|
+
trackingEdgeSwipe: false,
|
|
137
|
+
},
|
|
121
138
|
}
|
|
122
139
|
},
|
|
123
140
|
computed: {
|
|
@@ -142,10 +159,38 @@ export default {
|
|
|
142
159
|
},
|
|
143
160
|
mobileSidebarClass() {
|
|
144
161
|
if (this.isDesktopViewport) return ''
|
|
145
|
-
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
|
+
}
|
|
146
191
|
},
|
|
147
192
|
showSidebar() {
|
|
148
|
-
return this.isDesktopViewport || this.mobileSidebarOpen
|
|
193
|
+
return this.isDesktopViewport || this.mobileSidebarOpen || this.touchGesture.trackingEdgeSwipe
|
|
149
194
|
},
|
|
150
195
|
},
|
|
151
196
|
mounted() {
|
|
@@ -174,11 +219,55 @@ export default {
|
|
|
174
219
|
syncSidebarForViewport() {
|
|
175
220
|
if (!this.isDesktopViewport) {
|
|
176
221
|
this.mobileSidebarOpen = false
|
|
222
|
+
this.resetTouchState()
|
|
177
223
|
}
|
|
178
224
|
},
|
|
179
225
|
toggleMobileSidebar() {
|
|
180
226
|
if (this.isDesktopViewport) return
|
|
181
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
|
+
}
|
|
182
271
|
},
|
|
183
272
|
openExternalUrl() {
|
|
184
273
|
const target = String(this.externalUrl || '').trim()
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
type="button"
|
|
44
44
|
class="fixed bottom-0 left-0 z-50 inline-flex size-14 items-center justify-center rounded-tr-2xl transition-colors lg:hidden"
|
|
45
45
|
:class="theme === 'light'
|
|
46
|
-
? 'border border-
|
|
47
|
-
: 'bg-
|
|
46
|
+
? 'border border-rose-200 bg-rose-100 text-rose-900 shadow-lg shadow-slate-900/10 hover:bg-rose-200'
|
|
47
|
+
: ' bg-[#e63933] text-white shadow-lg shadow-black/25'"
|
|
48
48
|
aria-label="Open menu"
|
|
49
49
|
@click="toggleMenu">
|
|
50
50
|
<Menu class="size-6" :stroke-width="2.25" />
|
|
@@ -58,7 +58,6 @@ import MultilevelSidebar from "./MultilevelSidebar.vue";
|
|
|
58
58
|
|
|
59
59
|
const LG_VIEWPORT_QUERY = "(min-width: 1024px)";
|
|
60
60
|
const MAIN_MENU_TOGGLE_EVENT = "ketekny:two-col-layout-mobile-menu";
|
|
61
|
-
|
|
62
61
|
export default {
|
|
63
62
|
name: "TwoColLayout",
|
|
64
63
|
components: {
|