chore: init read-star monorepo
This commit is contained in:
147
apps/user/src/layouts/modules/global-tab/context-menu.vue
Normal file
147
apps/user/src/layouts/modules/global-tab/context-menu.vue
Normal file
@ -0,0 +1,147 @@
|
||||
<script setup lang="ts">
|
||||
import type { VNode } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useSvgIcon } from '@/hooks/common/icon'
|
||||
import { $t } from '@/locales'
|
||||
import { useTabStore } from '@/store/modules/tab'
|
||||
|
||||
defineOptions({
|
||||
name: 'ContextMenu',
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
excludeKeys: () => [],
|
||||
disabledKeys: () => [],
|
||||
})
|
||||
|
||||
interface Props {
|
||||
/** ClientX */
|
||||
x: number
|
||||
/** ClientY */
|
||||
y: number
|
||||
tabId: string
|
||||
excludeKeys?: App.Global.DropdownKey[]
|
||||
disabledKeys?: App.Global.DropdownKey[]
|
||||
}
|
||||
|
||||
const visible = defineModel<boolean>('visible')
|
||||
|
||||
const { removeTab, clearTabs, clearLeftTabs, clearRightTabs, fixTab, unfixTab, isTabRetain, homeTab } = useTabStore()
|
||||
const { SvgIconVNode } = useSvgIcon()
|
||||
|
||||
interface DropdownOption {
|
||||
key: App.Global.DropdownKey
|
||||
label: string
|
||||
icon?: () => VNode
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const options = computed(() => {
|
||||
const opts: DropdownOption[] = [
|
||||
{
|
||||
key: 'closeCurrent',
|
||||
label: $t('dropdown.closeCurrent'),
|
||||
icon: SvgIconVNode({ icon: 'ant-design:close-outlined', fontSize: 18 }),
|
||||
},
|
||||
{
|
||||
key: 'closeOther',
|
||||
label: $t('dropdown.closeOther'),
|
||||
icon: SvgIconVNode({ icon: 'ant-design:column-width-outlined', fontSize: 18 }),
|
||||
},
|
||||
{
|
||||
key: 'closeLeft',
|
||||
label: $t('dropdown.closeLeft'),
|
||||
icon: SvgIconVNode({ icon: 'mdi:format-horizontal-align-left', fontSize: 18 }),
|
||||
},
|
||||
{
|
||||
key: 'closeRight',
|
||||
label: $t('dropdown.closeRight'),
|
||||
icon: SvgIconVNode({ icon: 'mdi:format-horizontal-align-right', fontSize: 18 }),
|
||||
},
|
||||
{
|
||||
key: 'closeAll',
|
||||
label: $t('dropdown.closeAll'),
|
||||
icon: SvgIconVNode({ icon: 'ant-design:line-outlined', fontSize: 18 }),
|
||||
},
|
||||
]
|
||||
|
||||
if (props.tabId !== homeTab?.id) {
|
||||
if (isTabRetain(props.tabId)) {
|
||||
opts.push({
|
||||
key: 'unpin',
|
||||
label: $t('dropdown.unpin'),
|
||||
icon: SvgIconVNode({ icon: 'mdi:pin-off-outline', fontSize: 18 }),
|
||||
})
|
||||
}
|
||||
else {
|
||||
opts.push({
|
||||
key: 'pin',
|
||||
label: $t('dropdown.pin'),
|
||||
icon: SvgIconVNode({ icon: 'mdi:pin-outline', fontSize: 18 }),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const { excludeKeys, disabledKeys } = props
|
||||
|
||||
const result = opts.filter(opt => !excludeKeys.includes(opt.key))
|
||||
|
||||
disabledKeys.forEach((key) => {
|
||||
const opt = result.find(item => item.key === key)
|
||||
|
||||
if (opt) {
|
||||
opt.disabled = true
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
})
|
||||
|
||||
function hideDropdown() {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
const dropdownAction: Record<App.Global.DropdownKey, () => void> = {
|
||||
closeCurrent() {
|
||||
removeTab(props.tabId)
|
||||
},
|
||||
closeOther() {
|
||||
clearTabs([props.tabId])
|
||||
},
|
||||
closeLeft() {
|
||||
clearLeftTabs(props.tabId)
|
||||
},
|
||||
closeRight() {
|
||||
clearRightTabs(props.tabId)
|
||||
},
|
||||
closeAll() {
|
||||
clearTabs()
|
||||
},
|
||||
pin() {
|
||||
fixTab(props.tabId)
|
||||
},
|
||||
unpin() {
|
||||
unfixTab(props.tabId)
|
||||
},
|
||||
}
|
||||
|
||||
function handleDropdown(optionKey: App.Global.DropdownKey) {
|
||||
dropdownAction[optionKey]?.()
|
||||
hideDropdown()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NDropdown
|
||||
:show="visible"
|
||||
placement="bottom-start"
|
||||
trigger="manual"
|
||||
:x="x"
|
||||
:y="y"
|
||||
:options="options"
|
||||
@clickoutside="hideDropdown"
|
||||
@select="handleDropdown"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user