Files
speckle-server/packages/frontend-2/components/viewer/Sidebar.vue
T
andrewwallacespeckle efaad4b7e7 Panel title leading
2025-08-11 11:02:24 +01:00

95 lines
2.9 KiB
Vue

<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template>
<div
ref="resizableElement"
class="relative sm:absolute z-10 right-0 overflow-hidden w-screen bottom-0 sm:bottom-auto sm:top-[3.5rem] lg:top-[3rem] sm:right-2 lg:right-0 h-[40dvh] sm:h-[calc(100dvh-8rem)] lg:h-[calc(100dvh-3rem)] sm:max-w-[264px]"
:style="isLgOrLarger ? { maxWidth: width + 'px' } : {}"
:class="[open ? '' : 'pointer-events-none']"
>
<div class="flex h-full" :class="open ? '' : 'sm:translate-x-[100%]'">
<!-- Resize Handle -->
<div
ref="resizeHandle"
class="absolute h-full max-h-[calc(100dvh-3rem)] w-4 transition border-l sm:rounded-lg lg:rounded-none hover:border-l-[2px] border-outline-2 hover:border-primary hidden sm:flex items-center cursor-ew-resize z-30"
@mousedown="startResizing"
/>
<div
class="flex flex-col w-full h-full relative z-20 overflow-hidden sm:rounded-lg lg:rounded-none border-l border-t sm:border lg:border-0 lg:border-l border-outline-2 bg-foundation"
>
<div
class="h-10 pl-4 pr-2 flex items-center justify-between border-b border-outline-2"
>
<div class="text-body-xs text-foreground font-medium leading-none">
<slot name="title" />
</div>
<slot name="actions" />
</div>
<div class="simple-scrollbar overflow-y-auto h-full flex-1">
<slot />
</div>
<div v-if="$slots.footer" class="py-2 px-4 border-t border-outline-2">
<slot name="footer" />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useEventListener, useBreakpoints } from '@vueuse/core'
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
defineProps<{
open: boolean
}>()
const emit = defineEmits<{
(event: 'close'): void
(event: 'width-change', width: number): void
}>()
const resizableElement = ref(null)
const resizeHandle = ref(null)
const isResizing = ref(false)
const width = ref(280)
let startWidth = 0
let startX = 0
const breakpoints = useBreakpoints(TailwindBreakpoints)
const isLgOrLarger = breakpoints.greaterOrEqual('lg')
const startResizing = (event: MouseEvent) => {
event.preventDefault()
isResizing.value = true
startX = event.clientX
startWidth = width.value
}
if (import.meta.client) {
useEventListener(resizeHandle, 'mousedown', startResizing)
useEventListener(document, 'mousemove', (event) => {
if (isResizing.value) {
const diffX = startX - event.clientX
const newWidth = Math.max(
280,
Math.min(startWidth + diffX, Math.min(440, window.innerWidth * 0.5 - 60))
)
width.value = newWidth
emit('width-change', newWidth)
}
})
useEventListener(document, 'mouseup', () => {
if (isResizing.value) {
isResizing.value = false
}
})
}
onMounted(() => {
emit('width-change', width.value)
})
</script>