@@ -19,6 +19,10 @@ const props = withDefaults(defineProps<{
19
19
collapsed: false ,
20
20
float: true ,
21
21
})
22
+ const slots = defineSlots <{
23
+ default: () => any
24
+ }>()
25
+
22
26
const { uuid, collapsed, float } = toRefs (props )
23
27
24
28
// Panel
@@ -33,28 +37,23 @@ const { width } = useWindowSize()
33
37
const { height : windowHeight } = useWindowSize ()
34
38
const isInitialized = ref (false )
35
39
const isResizing = ref (false )
36
- const manualHeight = ref <number | null >(null ) // Track manual height override
37
40
38
41
const DEFAULT_WIDTH = 320
39
42
const COLLAPSED_SIZE = 36
40
- const MIN_HEIGHT = 160 // Minimum height for the panel
43
+ const MIN_HEIGHT = 148 // Minimum height for the panel
41
44
const MAX_HEIGHT = 600 // Maximum height for the panel
42
45
const CONTROL_HEIGHT = 44 // Approximate height per control
43
- const FPS_GRAPH_EXTRA_HEIGHT = 20 // Extra padding needed for FPS graph
46
+ const FPS_GRAPH_EXTRA_HEIGHT = 26 // Extra padding needed for FPS graph
44
47
45
48
const panelWidth = ref (DEFAULT_WIDTH )
46
49
const resizeEdge = ref <' right' | ' left' | ' bottom' | ' corner' | ' corner-left' | null >(null )
47
50
48
51
// Controls
49
52
const controls = useControlsProvider (uuid ?.value )
53
+ const hasSlots = ref (false )
50
54
51
55
defineExpose (controls )
52
56
53
- // Add cleanup when component is unmounted
54
- onUnmounted (() => {
55
- dispose (uuid ?.value )
56
- })
57
-
58
57
function onChange(key : string , value : string ) {
59
58
controls [key ].value = value
60
59
}
@@ -75,39 +74,30 @@ const groupedControls = computed(() => {
75
74
return groups
76
75
})
77
76
78
- const panelHeight = computed ({
79
- get : () => {
80
- if (isCollapsedAndNotFloat .value ) { return COLLAPSED_SIZE } // Height when collapsed
81
-
82
- // If manually resized, use that height within constraints
83
- if (manualHeight .value !== null ) {
84
- const maxAllowedHeight = float .value ? windowHeight .value : MAX_HEIGHT
85
- return Math .min (maxAllowedHeight , Math .max (MIN_HEIGHT , manualHeight .value ))
77
+ function calculateHeight() {
78
+ if (isCollapsedAndNotFloat .value ) { return COLLAPSED_SIZE } // Height when collapsed
79
+
80
+ // Calculate total controls including those in folders
81
+ let totalControls = 0
82
+ let hasFPSGraph = false
83
+ for (const folderName in groupedControls .value ) {
84
+ const controls = groupedControls .value [folderName ]
85
+ totalControls += controls .length
86
+ // Add height for folder header if it's not the default folder
87
+ if (folderName !== ' default' ) { totalControls += 1 }
88
+ // Check if there's an FPS graph control
89
+ if (controls .some (control => control .type === ' fpsgraph' )) {
90
+ hasFPSGraph = true
86
91
}
92
+ }
87
93
88
- // Calculate total controls including those in folders
89
- let totalControls = 0
90
- let hasFPSGraph = false
91
- for (const folderName in groupedControls .value ) {
92
- const controls = groupedControls .value [folderName ]
93
- totalControls += controls .length
94
- // Add height for folder header if it's not the default folder
95
- if (folderName !== ' default' ) { totalControls += 1 }
96
- // Check if there's an FPS graph control
97
- if (controls .some (control => control .type === ' fpsgraph' )) {
98
- hasFPSGraph = true
99
- }
100
- }
94
+ // Calculate height: header (32px) + controls + padding + extra for FPS if present
95
+ const calculatedHeight = 32 + (totalControls * CONTROL_HEIGHT ) + (hasFPSGraph ? FPS_GRAPH_EXTRA_HEIGHT : 0 )
96
+ const maxAllowedHeight = float .value ? windowHeight .value : MAX_HEIGHT
97
+ return Math .min (maxAllowedHeight , Math .max (MIN_HEIGHT , calculatedHeight ))
98
+ }
101
99
102
- // Calculate height: header (32px) + controls + padding + extra for FPS if present
103
- const calculatedHeight = 32 + (totalControls * CONTROL_HEIGHT ) + (hasFPSGraph ? FPS_GRAPH_EXTRA_HEIGHT : 0 )
104
- const maxAllowedHeight = float .value ? windowHeight .value : MAX_HEIGHT
105
- return Math .min (maxAllowedHeight , Math .max (MIN_HEIGHT , calculatedHeight ))
106
- },
107
- set : (value ) => {
108
- manualHeight .value = value
109
- },
110
- })
100
+ const panelHeight = ref (calculateHeight ())
111
101
112
102
const paneRef = ref <HTMLElement | null >(null )
113
103
const handleRef = ref <HTMLElement | null >(null )
@@ -178,7 +168,7 @@ function startResize(edge: 'right' | 'left' | 'bottom' | 'corner' | 'corner-left
178
168
const startX = e .clientX
179
169
const startY = e .clientY
180
170
const startWidth = panelWidth .value
181
- const startHeight = manualHeight . value ?? panelHeight .value
171
+ const startHeight = panelHeight .value
182
172
const startDragX = dragPosition .value .x
183
173
184
174
function onMouseMove(e : MouseEvent ) {
@@ -187,22 +177,20 @@ function startResize(edge: 'right' | 'left' | 'bottom' | 'corner' | 'corner-left
187
177
if (resizeEdge .value === ' right' || resizeEdge .value === ' corner' ) {
188
178
const deltaX = e .clientX - startX
189
179
panelWidth .value = Math .max (280 , startWidth + deltaX )
190
- paneRef .value .style .maxWidth = ` ${panelWidth .value }px `
191
180
}
192
181
193
182
if (resizeEdge .value === ' left' || resizeEdge .value === ' corner-left' ) {
194
183
const deltaX = startX - e .clientX
195
184
const newWidth = Math .max (280 , startWidth + deltaX )
196
185
dragPosition .value .x = startDragX - deltaX
197
186
panelWidth .value = newWidth
198
- paneRef .value .style .maxWidth = ` ${panelWidth .value }px `
199
187
}
200
188
201
189
if (resizeEdge .value === ' bottom' || resizeEdge .value === ' corner' || resizeEdge .value === ' corner-left' ) {
202
190
const deltaY = e .clientY - startY
203
191
const maxAllowedHeight = float .value ? windowHeight .value : MAX_HEIGHT
204
- manualHeight .value = Math .min (maxAllowedHeight , Math .max (MIN_HEIGHT , startHeight + deltaY ))
205
- paneRef . value . style . maxHeight = ` ${ manualHeight . value }px `
192
+ panelHeight .value = Math .min (maxAllowedHeight , Math .max (MIN_HEIGHT , startHeight + deltaY ))
193
+
206
194
// Update gradients after resize
207
195
handleScroll ()
208
196
}
@@ -221,29 +209,31 @@ function startResize(edge: 'right' | 'left' | 'bottom' | 'corner' | 'corner-left
221
209
document .addEventListener (' mouseup' , onMouseUp )
222
210
}
223
211
212
+ watch (panelHeight , (value ) => {
213
+ if (value && paneRef .value ) {
214
+ paneRef .value .style .maxHeight = ` ${value }px `
215
+ }
216
+ })
217
+
218
+ watch (panelWidth , (value ) => {
219
+ if (value && paneRef .value ) {
220
+ paneRef .value .style .maxWidth = ` ${value }px `
221
+ }
222
+ })
223
+
224
224
function toggleCollapsed() {
225
225
if (float .value ) {
226
226
isCollapsed .value = ! isCollapsed .value
227
227
}
228
228
}
229
229
230
- // Initialize panel after slot content is rendered
231
- onMounted (async () => {
232
- handleScroll ()
233
-
234
- // Wait for slot content to be rendered
235
- await nextTick ()
236
-
237
- isInitialized .value = true
238
- })
239
-
240
230
// Update animation when panel state changes
241
231
watch (isCollapsed , async (value ) => {
242
232
if (! value ) {
243
233
await nextTick () // Wait for slot to be visible
244
234
await apply ({
245
235
width: float .value ? panelWidth .value : ' none' ,
246
- height: float .value ? ( manualHeight . value || panelHeight .value ) : ' none' ,
236
+ height: float .value ? panelHeight .value : ' none' ,
247
237
right: float .value ? ' 1rem' : ' auto' ,
248
238
left: float .value ? ' auto' : ' 0' ,
249
239
})
@@ -254,11 +244,30 @@ watch(isCollapsed, async (value) => {
254
244
255
245
function onFolderOpen(value : boolean ) {
256
246
panelHeight .value = panelHeight .value + (44 * (value ? 1 : - 1 ))
257
- if (manualHeight .value && paneRef .value ) {
258
- manualHeight .value = manualHeight .value + (44 * (value ? 1 : - 1 ))
259
- paneRef .value .style .maxHeight = ` ${manualHeight .value }px `
260
- }
261
247
}
248
+
249
+ const slotsRef = ref ()
250
+
251
+ watch (slotsRef , (value ) => {
252
+ panelHeight .value = panelHeight .value + value .clientHeight
253
+ })
254
+
255
+ // Initialize panel after slot content is rendered
256
+ onMounted (async () => {
257
+ handleScroll ()
258
+
259
+ // Wait for slot content to be rendered
260
+ await nextTick ()
261
+
262
+ isInitialized .value = true
263
+
264
+ hasSlots .value = slots ?.default ? slots ?.default ().length > 0 : false
265
+ })
266
+
267
+ // Add cleanup when component is unmounted
268
+ onUnmounted (() => {
269
+ dispose (uuid ?.value )
270
+ })
262
271
</script >
263
272
264
273
<template >
@@ -303,7 +312,7 @@ function onFolderOpen(value: boolean) {
303
312
</button >
304
313
</div >
305
314
</header >
306
- <div v-show =" !isCollapsed" class =" tl-flex-1 tl-relative tl-overflow-hidden tl-my -4" >
315
+ <div v-show =" !isCollapsed" class =" tl-flex-1 tl-relative tl-overflow-hidden tl-py -4" >
307
316
<!-- Gradient overlays moved outside scrollable area -->
308
317
<div
309
318
class =" tl-pointer-events-none tl-absolute tl-left-0 tl-right-0 tl-top-0 tl-h-8 tl-bg-gradient-linear tl-bg-gradient-to-b tl-from-white dark:tl-from-dark-200 tl-to-transparent tl-z-20 tl-opacity-0 tl-transition-opacity duration-200"
@@ -337,7 +346,10 @@ function onFolderOpen(value: boolean) {
337
346
/>
338
347
</template >
339
348
</template >
340
- <slot ></slot >
349
+
350
+ <div v-if =" hasSlots" ref =" slotsRef" class =" tl-px-4" >
351
+ <slot ></slot >
352
+ </div >
341
353
</div >
342
354
</div >
343
355
<!-- Resize handles -->
0 commit comments