1
This commit is contained in:
1 parent
d1dda7f9fa
commit
ab310b49e9
6 files changed
+765
-327
No files matched your search
+103
-65
@@ -371,6 +371,7 @@ const tabScrollAreaRef = ref<HTMLElement | null>(null)
|
||||
const showTabScrollLeft = ref(false)
|
||||
const showTabScrollRight = ref(false)
|
||||
const isTabStripHover = ref(false)
|
||||
const isTabDragging = ref(false)
|
||||
const tabTitleOverflowMap = ref<Record<string, boolean>>({})
|
||||
let tabStripViewportEl: HTMLElement | null = null
|
||||
let tabTitleOverflowRafId: number | null = null
|
||||
@@ -544,6 +545,14 @@ const canMoveTab = (event: any) => {
|
||||
return true
|
||||
}
|
||||
|
||||
const handleTabDragStart = () => {
|
||||
isTabDragging.value = true
|
||||
}
|
||||
|
||||
const handleTabDragEnd = () => {
|
||||
isTabDragging.value = false
|
||||
}
|
||||
|
||||
const setTabItemRef = (id: string, el: Element | ComponentPublicInstance | null) => {
|
||||
if (el instanceof HTMLElement) {
|
||||
tabItemElMap.set(id, el)
|
||||
@@ -1341,9 +1350,9 @@ watch(
|
||||
<template>
|
||||
<TooltipProvider>
|
||||
<div class="flex flex-col w-full h-screen bg-background overflow-hidden">
|
||||
<div class="flex items-start gap-2 border-b bg-muted/30 px-2 pt-2 flex-none">
|
||||
<div class="flex items-start gap-2 border-b bg-muted/30 px-2 pt-1 min-h-14 flex-none">
|
||||
<div
|
||||
class="mb-2 flex min-w-0 flex-1 items-center gap-1"
|
||||
class="flex min-w-0 flex-1 items-start gap-1 h-full self-start"
|
||||
@mouseenter="isTabStripHover = true"
|
||||
@mouseleave="isTabStripHover = false"
|
||||
>
|
||||
@@ -1362,20 +1371,26 @@ watch(
|
||||
v-model="tabsModel"
|
||||
item-key="id"
|
||||
tag="div"
|
||||
class="flex w-max gap-1"
|
||||
:animation="180"
|
||||
:class="['tab-strip-sortable flex w-max gap-0', isTabDragging ? 'is-dragging' : '']"
|
||||
:animation="260"
|
||||
easing="cubic-bezier(0.22, 1, 0.36, 1)"
|
||||
ghost-class="tab-drag-ghost"
|
||||
chosen-class="tab-drag-chosen"
|
||||
drag-class="tab-drag-active"
|
||||
:move="canMoveTab"
|
||||
@start="handleTabDragStart"
|
||||
@end="handleTabDragEnd"
|
||||
>
|
||||
<template #item="{ element: tab }">
|
||||
<div
|
||||
:ref="el => setTabItemRef(tab.id, el)"
|
||||
@click="tabStore.activeTabId = tab.id"
|
||||
@mousedown.left="tabStore.activeTabId = tab.id"
|
||||
@contextmenu.prevent="openTabContextMenu($event, tab.id)"
|
||||
:class="[
|
||||
'group relative flex items-center h-9 px-4 min-w-[120px] max-w-[220px] cursor-pointer rounded-t-md border-x border-t transition-all text-sm',
|
||||
tabStore.activeTabId === tab.id
|
||||
? 'bg-background border-border font-medium'
|
||||
: 'border-transparent hover:bg-muted text-muted-foreground',
|
||||
'tab-item group relative -mb-px -ml-px first:ml-0 flex items-center h-10 px-4 min-w-[120px] max-w-[220px] cursor-pointer rounded-t-md border border-transparent transition-[background-color,border-color,color,box-shadow,transform] duration-200 text-sm',
|
||||
tabStore.activeTabId === tab.id && !isTabDragging
|
||||
? 'z-10 bg-background text-foreground !border-border !border-b-0 font-medium'
|
||||
: 'bg-muted/25 text-muted-foreground hover:bg-muted/40 hover:text-foreground hover:border-border/70',
|
||||
tab.id !== 'XmView' ? 'cursor-move' : ''
|
||||
]"
|
||||
>
|
||||
@@ -1415,12 +1430,12 @@ watch(
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div ref="dataMenuRef" class="relative mb-2 shrink-0">
|
||||
<div class="flex shrink-0 self-start items-start gap-1 mb-1">
|
||||
<div ref="dataMenuRef" class="relative shrink-0">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="h-9 min-h-9 px-3 py-0 text-sm leading-none cursor-pointer"
|
||||
class="h-9 min-h-9 shrink-0 px-3 py-0 text-sm leading-none cursor-pointer"
|
||||
@click="dataMenuOpen = !dataMenuOpen"
|
||||
>
|
||||
<ChevronDown class="h-4 w-4 mr-1" />
|
||||
@@ -1458,61 +1473,63 @@ watch(
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="mb-2 h-9 min-h-9 shrink-0 px-3 py-0 text-sm leading-none cursor-pointer"
|
||||
@click="openUserGuide(0)"
|
||||
>
|
||||
<CircleHelp class="h-4 w-4 mr-1" />
|
||||
使用引导
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="h-9 min-h-9 shrink-0 px-3 py-0 text-sm leading-none cursor-pointer"
|
||||
@click="openUserGuide(0)"
|
||||
>
|
||||
<CircleHelp class="h-4 w-4 mr-1" />
|
||||
使用引导
|
||||
</Button>
|
||||
|
||||
<AlertDialogRoot>
|
||||
<AlertDialogTrigger as-child>
|
||||
<Button variant="destructive" size="sm" class="mb-2 h-9 min-h-9 shrink-0 px-3 py-0 text-sm leading-none">
|
||||
<RotateCcw class="h-4 w-4 mr-1" />
|
||||
重置
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay class="fixed inset-0 z-50 bg-black/45" />
|
||||
<AlertDialogContent class="fixed left-1/2 top-1/2 z-50 w-[92vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border bg-background p-5 shadow-xl">
|
||||
<AlertDialogTitle class="text-base font-semibold">确认重置</AlertDialogTitle>
|
||||
<AlertDialogDescription class="mt-2 text-sm text-muted-foreground">
|
||||
将清空所有项目数据,并恢复默认页面,确认继续吗?
|
||||
</AlertDialogDescription>
|
||||
<div class="mt-4 flex items-center justify-end gap-2">
|
||||
<AlertDialogCancel as-child>
|
||||
<Button variant="outline">取消</Button>
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction as-child>
|
||||
<Button variant="destructive" @click="handleReset">确认重置</Button>
|
||||
</AlertDialogAction>
|
||||
</div>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogPortal>
|
||||
</AlertDialogRoot>
|
||||
<AlertDialogRoot>
|
||||
<AlertDialogTrigger as-child>
|
||||
<Button variant="destructive" size="sm" class="h-9 min-h-9 shrink-0 px-3 py-0 text-sm leading-none cursor-pointer">
|
||||
<RotateCcw class="h-4 w-4 mr-1" />
|
||||
重置
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay class="fixed inset-0 z-50 bg-black/45" />
|
||||
<AlertDialogContent class="fixed left-1/2 top-1/2 z-50 w-[92vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border bg-background p-5 shadow-xl">
|
||||
<AlertDialogTitle class="text-base font-semibold">确认重置</AlertDialogTitle>
|
||||
<AlertDialogDescription class="mt-2 text-sm text-muted-foreground">
|
||||
将清空所有项目数据,并恢复默认页面,确认继续吗?
|
||||
</AlertDialogDescription>
|
||||
<div class="mt-4 flex items-center justify-end gap-2">
|
||||
<AlertDialogCancel as-child>
|
||||
<Button variant="outline">取消</Button>
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction as-child>
|
||||
<Button variant="destructive" @click="handleReset">确认重置</Button>
|
||||
</AlertDialogAction>
|
||||
</div>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogPortal>
|
||||
</AlertDialogRoot>
|
||||
|
||||
<AlertDialogRoot :open="importConfirmOpen" @update:open="importConfirmOpen = $event">
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay class="fixed inset-0 z-50 bg-black/45" />
|
||||
<AlertDialogContent class="fixed left-1/2 top-1/2 z-50 w-[92vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border bg-background p-5 shadow-xl">
|
||||
<AlertDialogTitle class="text-base font-semibold">确认导入覆盖</AlertDialogTitle>
|
||||
<AlertDialogDescription class="mt-2 text-sm text-muted-foreground">
|
||||
将使用“{{ pendingImportFileName || '所选文件' }}”覆盖当前本地全部数据,是否继续?
|
||||
</AlertDialogDescription>
|
||||
<div class="mt-4 flex items-center justify-end gap-2">
|
||||
<AlertDialogCancel as-child>
|
||||
<Button variant="outline" @click="cancelImportConfirm">取消</Button>
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction as-child>
|
||||
<Button variant="destructive" @click="confirmImportOverride">确认覆盖</Button>
|
||||
</AlertDialogAction>
|
||||
</div>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogPortal>
|
||||
</AlertDialogRoot>
|
||||
<AlertDialogRoot :open="importConfirmOpen" @update:open="importConfirmOpen = $event">
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay class="fixed inset-0 z-50 bg-black/45" />
|
||||
<AlertDialogContent class="fixed left-1/2 top-1/2 z-50 w-[92vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border bg-background p-5 shadow-xl">
|
||||
<AlertDialogTitle class="text-base font-semibold">确认导入覆盖</AlertDialogTitle>
|
||||
<AlertDialogDescription class="mt-2 text-sm text-muted-foreground">
|
||||
将使用“{{ pendingImportFileName || '所选文件' }}”覆盖当前本地全部数据,是否继续?
|
||||
</AlertDialogDescription>
|
||||
<div class="mt-4 flex items-center justify-end gap-2">
|
||||
<AlertDialogCancel as-child>
|
||||
<Button variant="outline" @click="cancelImportConfirm">取消</Button>
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction as-child>
|
||||
<Button variant="destructive" @click="confirmImportOverride">确认覆盖</Button>
|
||||
</AlertDialogAction>
|
||||
</div>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogPortal>
|
||||
</AlertDialogRoot>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-auto relative">
|
||||
@@ -1612,6 +1629,27 @@ watch(
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.tab-strip-sortable > .tab-item {
|
||||
transition: transform 0.26s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.tab-strip-sortable.is-dragging > .tab-item {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.tab-drag-ghost {
|
||||
opacity: 0.32;
|
||||
}
|
||||
|
||||
.tab-drag-chosen {
|
||||
transform: scale(1.015);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 18%);
|
||||
}
|
||||
|
||||
.tab-drag-active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.tab-strip-scroll-area :deep([data-slot="scroll-area-viewport"]) {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user