Resizeable property selection panel

This commit is contained in:
andrewwallacespeckle
2025-09-11 16:49:11 +01:00
parent 0afdaf5fc0
commit 0779dbd968
2 changed files with 78 additions and 45 deletions
@@ -166,9 +166,15 @@
<!-- Panel Extension - Portal target for additional content -->
<div
id="panel-extension"
class="absolute z-50 left-[calc(100dvw-20rem)] md:left-72 max-h-[calc(100dvh-6rem)] md:max-h-[calc(100dvh-4rem)] empty:hidden w-64 top-1.5 bg-foundation border border-outline-2 rounded-lg overflow-hidden"
:style="`left: ${panelExtensionLeft} !important`"
class="absolute z-50 left-[calc(100dvw-20rem)] md:left-72 max-h-[calc(100dvh-6rem)] md:max-h-[calc(100dvh-4rem)] top-1.5 bg-foundation rounded-lg overflow-hidden"
:style="`left: ${panelExtensionLeft} !important; width: ${panelExtensionWidth}px;`"
>
<!-- Resize handle for panel extension -->
<div
ref="panelExtensionResizeHandle"
class="absolute h-full max-h-[calc(100dvh-6rem)] md:max-h-[calc(100dvh-4rem)] w-4 transition border-r hover:border-r-[2px] border-outline-2 hover:border-primary hidden lg:flex items-center cursor-ew-resize z-30 right-0"
@mousedown="startPanelExtensionResizing"
/>
<PortalTarget name="panel-extension"></PortalTarget>
</div>
</aside>
@@ -212,49 +218,7 @@ const emit = defineEmits<{
forceClosePanels: []
}>()
const width = ref(264)
const scrollableControlsContainer = ref(null as Nullable<HTMLDivElement>)
const height = ref(scrollableControlsContainer.value?.clientHeight)
const isResizing = ref(false)
const resizeHandle = ref(null)
const { width: windowWidth } = useWindowSize()
let startWidth = 0
let startX = 0
const startResizing = (event: MouseEvent) => {
if (isMobile.value) return
event.preventDefault()
isResizing.value = true
startX = event.clientX
startWidth = width.value
}
const throttledHandleMouseMove = useThrottleFn((event: MouseEvent) => {
if (isResizing.value) {
const diffX = event.clientX - startX
const newWidth = Math.max(
240,
Math.min(startWidth + diffX, Math.min(440, windowWidth.value * 0.5 - 60))
)
width.value = newWidth
}
}, 150)
if (import.meta.client) {
useResizeObserver(scrollableControlsContainer, (entries) => {
const { height: newHeight } = entries[0].contentRect
height.value = newHeight
})
useEventListener(resizeHandle, 'mousedown', startResizing)
useEventListener(document, 'mousemove', throttledHandleMouseMove)
useEventListener(document, 'mouseup', () => {
if (isResizing.value) {
isResizing.value = false
}
})
}
const { isIntercomEnabled } = useIntercomEnabled()
const { resourceItems, modelsAndVersionIds } = useInjectedViewerLoadedResources()
@@ -263,6 +227,7 @@ const { isEnabled: isEmbedEnabled } = useEmbed()
const breakpoints = useBreakpoints(TailwindBreakpoints)
const isMobile = breakpoints.smaller('sm')
const isTablet = breakpoints.smaller('lg')
const isLargerThanLg = breakpoints.greater('lg')
const { getTooltipProps } = useSmartTooltipDelay()
const isSavedViewsEnabled = useAreSavedViewsEnabled()
const isWorkspacesEnabled = useIsWorkspacesEnabled()
@@ -278,6 +243,74 @@ const {
const { onPanelButtonClick } = useViewerPanelsUtilities()
const width = ref(264)
const panelExtensionWidth = ref(isMobile.value ? 200 : isLargerThanLg.value ? 300 : 256)
const scrollableControlsContainer = ref(null as Nullable<HTMLDivElement>)
const height = ref(scrollableControlsContainer.value?.clientHeight)
const isResizing = ref(false)
const isPanelExtensionResizing = ref(false)
const resizeHandle = ref(null)
const panelExtensionResizeHandle = ref(null)
let startWidth = 0
let startX = 0
let startPanelExtensionWidth = 0
let startPanelExtensionX = 0
const startResizing = (event: MouseEvent) => {
if (isMobile.value) return
event.preventDefault()
isResizing.value = true
startX = event.clientX
startWidth = width.value
}
const startPanelExtensionResizing = (event: MouseEvent) => {
if (isMobile.value) return
event.preventDefault()
isPanelExtensionResizing.value = true
startPanelExtensionX = event.clientX
startPanelExtensionWidth = panelExtensionWidth.value
}
const throttledHandleMouseMove = useThrottleFn((event: MouseEvent) => {
if (isResizing.value) {
const diffX = event.clientX - startX
const newWidth = Math.max(
240,
Math.min(startWidth + diffX, Math.min(440, windowWidth.value * 0.5 - 60))
)
width.value = newWidth
} else if (isPanelExtensionResizing.value) {
const diffX = event.clientX - startPanelExtensionX
const newWidth = Math.max(
200,
Math.min(startPanelExtensionWidth + diffX, Math.min(400, windowWidth.value * 0.4))
)
panelExtensionWidth.value = newWidth
}
}, 150)
if (import.meta.client) {
useResizeObserver(scrollableControlsContainer, (entries) => {
const { height: newHeight } = entries[0].contentRect
height.value = newHeight
})
useEventListener(resizeHandle, 'mousedown', startResizing)
useEventListener(panelExtensionResizeHandle, 'mousedown', startPanelExtensionResizing)
useEventListener(document, 'mousemove', throttledHandleMouseMove)
useEventListener(document, 'mouseup', () => {
if (isResizing.value) {
isResizing.value = false
}
if (isPanelExtensionResizing.value) {
isPanelExtensionResizing.value = false
}
})
}
const hasActivePanel = computed(() => activePanel.value !== 'none')
const allAutomationRuns = computed(() => {
@@ -1,5 +1,5 @@
<template>
<div class="h-full flex flex-col select-none">
<div class="h-full flex flex-col select-none border border-outline-2 rounded-lg">
<ViewerFiltersPropertySelectionSearch
v-model="searchQuery"
placeholder="Search for a property..."