refactor: wrapping element with drag and resize behavior as a standalone component

This commit is contained in:
tiny-craft 2023-10-27 18:26:35 +08:00
parent b6eebda177
commit 124627d724
5 changed files with 152 additions and 74 deletions

View File

@ -16,6 +16,7 @@ import ToolbarControlWidget from '@/components/common/ToolbarControlWidget.vue'
import { EventsOn, WindowIsFullscreen, WindowIsMaximised, WindowToggleMaximise } from 'wailsjs/runtime/runtime.js'
import { isMacOS } from '@/utils/platform.js'
import iconUrl from '@/assets/images/icon.png'
import ResizeableWrapper from '@/components/common/ResizeableWrapper.vue'
const themeVars = useThemeVars()
@ -25,8 +26,6 @@ const props = defineProps({
const data = reactive({
navMenuWidth: 60,
hoverResize: false,
resizing: false,
toolbarHeight: 45,
})
@ -38,32 +37,9 @@ const logPaneRef = ref(null)
// provide('preferences', preferences)
const saveSidebarWidth = debounce(prefStore.savePreferences, 1000, { trailing: true })
const handleResize = (evt) => {
if (data.resizing) {
prefStore.setAsideWidth(Math.max(evt.clientX - data.navMenuWidth, 300))
const handleResize = () => {
saveSidebarWidth()
}
}
const stopResize = () => {
data.resizing = false
document.removeEventListener('mousemove', handleResize)
document.removeEventListener('mouseup', stopResize)
}
const startResize = () => {
data.resizing = true
document.addEventListener('mousemove', handleResize)
document.addEventListener('mouseup', stopResize)
}
const asideWidthVal = computed(() => {
return prefStore.behavior.asideWidth + 'px'
})
const dragging = computed(() => {
return data.hoverResize || data.resizing
})
watch(
() => tabStore.nav,
@ -166,15 +142,6 @@ onMounted(async () => {
</transition>
</n-space>
</div>
<div
:class="{
'resize-divider-hover': data.hoverResize,
'resize-divider-drag': data.resizing,
}"
class="resize-divider resize-divider-hide"
@mousedown="startResize"
@mouseout="data.hoverResize = false"
@mouseover="data.hoverResize = true" />
<!-- browser tabs -->
<div v-show="tabStore.nav === 'browser'" class="app-toolbar-tab flex-item-expand">
<content-value-tab />
@ -196,23 +163,19 @@ onMounted(async () => {
style="--wails-draggable: none">
<nav-menu v-model:value="tabStore.nav" :width="data.navMenuWidth" />
<!-- browser page -->
<div v-show="tabStore.nav === 'browser'" :class="{ dragging }" class="flex-box-h flex-item-expand">
<div :style="{ width: asideWidthVal }" class="app-side flex-box-h flex-item">
<div v-show="tabStore.nav === 'browser'" class="flex-box-h flex-item-expand">
<resizeable-wrapper
v-model:size="prefStore.behavior.asideWidth"
:min-size="300"
:offset="data.navMenuWidth"
class="flex-item"
@update:size="handleResize">
<browser-pane
v-for="t in tabStore.tabs"
v-show="get(tabStore.currentTab, 'name') === t.name"
:key="t.name"
class="flex-item-expand" />
<div
:class="{
'resize-divider-hover': data.hoverResize,
'resize-divider-drag': data.resizing,
}"
class="resize-divider"
@mousedown="startResize"
@mouseout="data.hoverResize = false"
@mouseover="data.hoverResize = true" />
</div>
class="app-side flex-item-expand" />
</resizeable-wrapper>
<content-pane
v-for="t in tabStore.tabs"
v-show="get(tabStore.currentTab, 'name') === t.name"
@ -222,19 +185,15 @@ onMounted(async () => {
</div>
<!-- server list page -->
<div v-show="tabStore.nav === 'server'" :class="{ dragging }" class="flex-box-h flex-item-expand">
<div :style="{ width: asideWidthVal }" class="app-side flex-box-h flex-item">
<connection-pane class="flex-item-expand" />
<div
:class="{
'resize-divider-hover': data.hoverResize,
'resize-divider-drag': data.resizing,
}"
class="resize-divider"
@mousedown="startResize"
@mouseout="data.hoverResize = false"
@mouseover="data.hoverResize = true" />
</div>
<div v-show="tabStore.nav === 'server'" class="flex-box-h flex-item-expand">
<resizeable-wrapper
v-model:size="prefStore.behavior.asideWidth"
:min-size="300"
:offset="data.navMenuWidth"
class="flex-item"
@update:size="handleResize">
<connection-pane class="app-side flex-item-expand" />
</resizeable-wrapper>
<content-server-pane class="flex-item-expand" />
</div>
@ -282,6 +241,7 @@ onMounted(async () => {
//overflow: hidden;
height: 100%;
background-color: v-bind('themeVars.tabColor');
border-right: 1px solid v-bind('themeVars.borderColor');
}
}
@ -305,10 +265,6 @@ onMounted(async () => {
border-right-color: v-bind('themeVars.primaryColor');
}
.dragging {
cursor: col-resize !important;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;

View File

@ -0,0 +1,122 @@
<script setup>
import { useThemeVars } from 'naive-ui'
import { ref } from 'vue'
/**
* Resizeable component wrapper
*/
const themeVars = useThemeVars()
const props = defineProps({
size: {
type: Number,
default: 100,
},
minSize: {
type: Number,
default: 300,
},
maxSize: {
type: Number,
default: 0,
},
offset: {
type: Number,
default: 0,
},
disabled: {
type: Boolean,
default: false,
},
borderWidth: {
type: Number,
default: 4,
},
})
const emit = defineEmits(['update:size'])
const resizing = ref(false)
const hover = ref(false)
const handleResize = (evt) => {
if (resizing.value) {
let size = evt.clientX - props.offset
if (size < props.minSize) {
size = props.minSize
}
if (props.maxSize > 0 && size > props.maxSize) {
size = props.maxSize
}
emit('update:size', size)
}
}
const stopResize = () => {
resizing.value = false
document.removeEventListener('mousemove', handleResize)
document.removeEventListener('mouseup', stopResize)
}
const startResize = () => {
if (props.disabled) {
return
}
resizing.value = true
document.addEventListener('mousemove', handleResize)
document.addEventListener('mouseup', stopResize)
}
const handleMouseOver = () => {
if (props.disabled) {
return
}
hover.value = true
}
</script>
<template>
<div :style="{ width: props.size + 'px' }" class="resize-wrapper flex-box-h">
<slot></slot>
<div
:class="{
'resize-divider-hover': hover,
'resize-divider-drag': resizing,
dragging: hover || resizing,
}"
:style="{ width: props.borderWidth + 'px', right: Math.floor(-props.borderWidth / 2) + 'px' }"
class="resize-divider"
@mousedown="startResize"
@mouseout="hover = false"
@mouseover="handleMouseOver" />
</div>
</template>
<style lang="scss" scoped>
.resize-wrapper {
position: relative;
.resize-divider {
position: absolute;
top: 0;
bottom: 0;
transition: background-color 0.3s ease-in;
}
.resize-divider-hide {
background-color: #0000;
}
.resize-divider-hover {
background-color: v-bind('themeVars.borderColor');
}
.resize-divider-drag {
background-color: v-bind('themeVars.primaryColor');
}
.dragging {
cursor: col-resize !important;
}
}
</style>

View File

@ -17,13 +17,13 @@ const tabStore = useTabStore()
const connectionStore = useConnectionStore()
const onCloseTab = (tabIndex) => {
$dialog.warning(i18n.t('dialogue.close_confirm'), () => {
const tab = get(tabStore.tabs, tabIndex)
if (tab != null) {
$dialog.warning(i18n.t('dialogue.close_confirm', { name: tab.name }), () => {
connectionStore.closeConnection(tab.name)
}
})
}
}
const tabMarkColor = computed(() => {
const { name } = tabStore?.currentTab || {}
@ -53,7 +53,7 @@ const tab = computed(() =>
<n-tabs
v-model:value="tabStore.activatedIndex"
:closable="true"
:tabs-padding="0"
:tabs-padding="3"
:theme-overrides="{
tabFontWeightActive: 800,
tabGapSmallCard: 0,

View File

@ -108,7 +108,7 @@
"log": "Log"
},
"dialogue": {
"close_confirm": "Confirm close this tab and connection",
"close_confirm": "Confirm close this tab and connection ({name})",
"edit_close_confirm": "Please close the relevant connections before editing. Do you want to continue?",
"opening_connection": "Opening Connection...",
"interrupt_connection": "Cancel",

View File

@ -108,7 +108,7 @@
"log": "日志"
},
"dialogue": {
"close_confirm": "是否关闭当前连接",
"close_confirm": "是否关闭此连接({name}",
"edit_close_confirm": "编辑前需要关闭相关连接,是否继续",
"opening_connection": "正在打开连接...",
"interrupt_connection": "中断连接",