RSS Git Download  Clone
Raw Blame History 6kB 186 lines
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useRedisStateStore } from '../stores/redis-state'
import { useThemeStore } from '../stores/theme'
import ConsoleComponent from '../pages/console/ConsoleComponent.vue'

const HEIGHT_KEY = 'p3xr-console-drawer-height'
const MIN_VH = 15
const MAX_VH = 66
const FOOTER_HEIGHT = 48

const state = useRedisStateStore()
const { themeKey } = storeToRefs(useThemeStore())
const isOpen = computed(() => state.consoleDrawerOpen)

const ACCORDION_BG: Record<string, string> = {
    enterprise: '#9e9e9e', light: '#b0bec5', redis: '#ef9a9a',
    dark: '#9e9e9e', darkNeu: '#90a4ae', darkoBluo: '#3f51b5',
    matrix: '#76ff03',
}
const borderColor = computed(() => ACCORDION_BG[themeKey.value])

const resizeClicked = ref(false)
const sizerHover = ref(false)
const drawerRef = ref<HTMLElement | null>(null)

let dragStyleEl: HTMLStyleElement | null = null
let drawerResizeObserver: ResizeObserver | null = null

function applyDragCursor(cursor: 'ns-resize' | 'not-allowed') {
    if (!dragStyleEl) {
        dragStyleEl = document.createElement('style')
        dragStyleEl.setAttribute('data-p3xr-console-drawer-drag', '')
        document.head.appendChild(dragStyleEl)
    }
    dragStyleEl.textContent = `*, *::before, *::after { cursor: ${cursor} !important; }`
}

function clearDragCursor() {
    dragStyleEl?.remove()
    dragStyleEl = null
}

// Saved height is applied at bootstrap (src/core/console-drawer-height.ts)
// so it's in place before this component mounts.

function handleSizerMouseDown(e: MouseEvent) {
    e.preventDefault()
    e.stopPropagation()
    resizeClicked.value = true
    applyDragCursor('ns-resize')
    document.body.classList.add('p3xr-not-selectable')
    document.documentElement.classList.add('p3xr-console-drawer-resizing')
}

function onMouseMove(e: MouseEvent) {
    if (!resizeClicked.value) return
    const minPx = (MIN_VH / 100) * window.innerHeight
    const maxPx = (MAX_VH / 100) * window.innerHeight
    let newHeight = window.innerHeight - e.clientY - FOOTER_HEIGHT
    const outOfBounds = newHeight < minPx || newHeight > maxPx
    if (newHeight < minPx) newHeight = minPx
    if (newHeight > maxPx) newHeight = maxPx
    applyDragCursor(outOfBounds ? 'not-allowed' : 'ns-resize')
    document.documentElement.style.setProperty('--p3xr-console-drawer-height', `${Math.round(newHeight)}px`)
}

function onMouseUp() {
    if (!resizeClicked.value) return
    resizeClicked.value = false
    clearDragCursor()
    document.body.classList.remove('p3xr-not-selectable')
    document.documentElement.classList.remove('p3xr-console-drawer-resizing')
    const current = document.documentElement.style.getPropertyValue('--p3xr-console-drawer-height')
    if (current && current.endsWith('px')) {
        localStorage.setItem(HEIGHT_KEY, current)
    }
}

onMounted(() => {
    document.addEventListener('mousemove', onMouseMove)
    document.addEventListener('mouseup', onMouseUp)
    // Observe the drawer element — fires on every size change frame
    // (open/close transition + live drag). Listeners on window.resize
    // (profiler/pubsub page height calc) pick it up.
    if (drawerRef.value && typeof ResizeObserver !== 'undefined') {
        drawerResizeObserver = new ResizeObserver(() => {
            window.dispatchEvent(new Event('resize'))
        })
        drawerResizeObserver.observe(drawerRef.value)
    }
})

onUnmounted(() => {
    document.removeEventListener('mousemove', onMouseMove)
    document.removeEventListener('mouseup', onMouseUp)
    drawerResizeObserver?.disconnect()
    drawerResizeObserver = null
    clearDragCursor()
})

function close() {
    state.setConsoleDrawerOpen(false)
}
</script>

<template>
    <div ref="drawerRef"
         id="p3xr-console-drawer"
         :class="{ 'p3xr-drawer-open': isOpen }"
         :style="{ borderColor: borderColor, transition: resizeClicked ? 'none' : 'height 150ms ease-out' }">
        <div id="p3xr-console-drawer-sizer"
             role="separator"
             aria-orientation="horizontal"
             aria-label="Resize console drawer"
             :class="{ 'p3xr-resizer-hover': sizerHover, 'p3xr-resizer-active': resizeClicked }"
             @mousedown="handleSizerMouseDown"
             @mouseenter="sizerHover = true"
             @mouseleave="sizerHover = false"
             :style="{ backgroundColor: (sizerHover || resizeClicked) ? borderColor : 'transparent' }"></div>
        <div id="p3xr-console-drawer-body">
            <ConsoleComponent :embedded="true"
                              :show-close-button="true"
                              @close-request="close" />
        </div>
    </div>
</template>

<style>
#p3xr-console-drawer {
    position: fixed;
    left: 5px;
    right: calc(5px + var(--p3xr-scroll-gutter, 0px));
    bottom: 48px;
    height: 0;
    overflow: hidden;
    background-color: rgb(var(--v-theme-surface));
    color: rgba(var(--v-theme-on-surface), 0.87);
    border: 0 solid;
    border-radius: 4px 4px 0 0;
    z-index: 8;
    transition: height 150ms ease-out;
    display: flex;
    flex-direction: column;
}
#p3xr-console-drawer.p3xr-drawer-open {
    height: var(--p3xr-console-drawer-height, 30vh);
    border-width: 1px;
}
#p3xr-console-drawer-sizer {
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 5px;
    cursor: ns-resize;
    z-index: 3;
    background-color: transparent;
    transition: background-color 0.15s ease, filter 0.15s ease;
}
body.p3xr-theme-dark #p3xr-console-drawer-sizer.p3xr-resizer-hover {
    filter: brightness(1.5);
}
body.p3xr-theme-dark #p3xr-console-drawer-sizer.p3xr-resizer-active {
    filter: brightness(2);
}
body.p3xr-theme-light #p3xr-console-drawer-sizer.p3xr-resizer-hover {
    filter: brightness(0.75);
}
body.p3xr-theme-light #p3xr-console-drawer-sizer.p3xr-resizer-active {
    filter: brightness(0.5);
}
#p3xr-console-drawer-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    position: relative;
}
#p3xr-console-drawer-body > * {
    width: 100%;
    height: 100%;
}
:root {
    --p3xr-console-drawer-height: 30vh;
}
</style>