Files
speckle-server/packages/frontend-2/components/viewer/Sidebar.vue
T
Benjamin Ottensten fc76fd9f4f Various polishing around the product (#2427)
* Update header navigation

Logo, share button color, breadcrumb colors, spacings

* Updates to main button component

Shadows, border on secondary button, less spacings to icons

* Update spacings in dialog after bew button styling

* Use secondary button in embed dialog

* Update select inputs

Spacing, icon, border on dropdown, smaller avatars

* Update inputs to use the new styling

* Various copy updates

* Update icons

Smaller icons, outline instead of solid, removed some icons that were unnecessary

* Switch order of actions in Delete dialog

* Update styling of inline New model action

* Remove strange BG effect on comments component

* Update styling of hide/isolate actions in viewer

Was necessary after the button styling change. But new copy also makes it more usable.

* Fix alignment issue in selection info panel

* Align styling in Viewer panel component

* Clean up measure usage tips

A permanent "Right click to cancel measurement" tip isn't needed

* Panel spacing

* Update actions in the add model to viewer dialog

* Update permissions input in new project dialog

* Two minor things

* Remove unnecessary flex classes

---------

Co-authored-by: andrewwallacespeckle <andrew@speckle.systems>
2024-06-25 14:43:50 +02:00

139 lines
4.3 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 sm:pr-3 sm:pb-3 sm:pt-0"
:style="!isSmallerOrEqualSm ? { maxWidth: width + 'px' } : {}"
:class="[
open ? '' : 'pointer-events-none',
isEmbedEnabled === true
? 'sm:top-2 sm:h-[calc(100dvh-3.8rem)]'
: 'sm:top-[4.2rem] sm:h-[calc(100dvh-4.2rem)]'
]"
>
<div
class="flex transition-all h-full"
:class="open ? '' : 'sm:translate-x-[100%]'"
>
<!-- Resize Handle -->
<div
ref="resizeHandle"
class="hidden sm:flex group relative z-30 hover:z-50 w-6 h-full items-center overflow-hidden -mr-1"
>
<div
class="w-5 h-8 mr-1 bg-foundation group-hover:bg-outline-2 rounded-l translate-x-3 group-hover:translate-x-0.5 transition cursor-ew-resize flex items-center justify-center group-hover:shadow-xl"
@mousedown="startResizing"
>
<ArrowsRightLeftIcon
class="h-3 w-3 transition opacity-0 group-hover:opacity-80 text-outline-1 -ml-px"
/>
</div>
<div
class="relative z-30 w-1 h-full pt-[4.2rem] -ml-1 bg-transparent group-hover:bg-outline-2 cursor-ew-resize transition rounded-l"
@mousedown="startResizing"
></div>
</div>
<div
class="flex flex-col w-full h-full relative z-20 overflow-hidden shadow-lg rounded-b-md"
>
<!-- Header -->
<div
class="h-[4.5rem] absolute z-10 top-0 w-full left-0 bg-foundation shadow-md sm:rounded-t-md"
>
<div
class="flex items-center justify-between pl-3 pr-2.5 h-10 border-b border-outline-3"
>
<div v-if="$slots.title" class="font-bold text-sm text-primary">
<slot name="title"></slot>
</div>
<div class="flex items-center gap-0.5">
<button class="p-0.5 text-foreground hover:text-primary" @click="onClose">
<XMarkIcon class="size-4" />
</button>
</div>
</div>
<div v-if="$slots.actions" class="w-full px-2 h-8">
<div class="flex items-center gap-1 h-full">
<slot name="actions"></slot>
</div>
</div>
</div>
<div class="w-full" :class="$slots.actions ? 'h-[4.5rem]' : 'h-10'"></div>
<div
class="overflow-y-auto simple-scrollbar h-full bg-foundation w-full pt-2 sm:rounded-b-md"
>
<slot></slot>
</div>
<div
v-if="$slots.footer"
class="absolute z-20 bottom-0 h-8 bg-foundation shadow-t w-full flex items-center px-3 empty:translate-y-10 transition sm:rounded-b-md"
>
<slot name="footer"></slot>
</div>
<div v-if="$slots.footer" class="h-8"></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useEventListener } from '@vueuse/core'
import { XMarkIcon, ArrowsRightLeftIcon } from '@heroicons/vue/24/outline'
import { useIsSmallerOrEqualThanBreakpoint } from '~~/composables/browser'
import { useEmbed } from '~/lib/viewer/composables/setup/embed'
defineProps<{
open: boolean
}>()
const emit = defineEmits<{
(event: 'close'): void
}>()
const resizableElement = ref(null)
const resizeHandle = ref(null)
const isResizing = ref(false)
const width = ref(300)
let startWidth = 0
let startX = 0
const { isSmallerOrEqualSm } = useIsSmallerOrEqualThanBreakpoint()
const { isEnabled: isEmbedEnabled } = useEmbed()
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
width.value = Math.max(
300,
Math.min(startWidth + diffX, (parseInt('75vw') * window.innerWidth) / 100)
)
}
})
useEventListener(document, 'mouseup', () => {
if (isResizing.value) {
isResizing.value = false
}
})
}
const minimize = () => {
width.value = 300
}
const onClose = () => {
minimize()
emit('close')
}
</script>