feat: 为ssh标签栏和文件编辑器标签栏添加右键菜单

This commit is contained in:
Baobhan Sith
2025-05-03 19:43:50 +08:00
parent 23a470a6a0
commit 88ad7332a3
11 changed files with 620 additions and 47 deletions
@@ -0,0 +1,103 @@
<script setup lang="ts">
import { computed, PropType } from 'vue';
import { useI18n } from 'vue-i18n';
interface MenuItem {
label: string;
action: string;
disabled?: boolean; // 可选:是否禁用
isSeparator?: boolean; // 可选:是否是分隔线
isDanger?: boolean; // 可选:是否是危险操作 (例如红色文本)
}
const props = defineProps({
visible: {
type: Boolean,
required: true,
},
position: {
type: Object as PropType<{ x: number; y: number }>,
required: true,
},
items: {
type: Array as PropType<MenuItem[]>,
required: true,
},
// + Add targetId prop
targetId: {
type: [String, Number, null] as PropType<string | number | null>,
default: null,
}
});
const emit = defineEmits<{
// + Update signature to include targetId
(e: 'menu-action', payload: { action: string; targetId: string | number | null }): void;
(e: 'close'): void; // 请求关闭菜单
}>();
const { t } = useI18n();
const menuStyle = computed(() => ({
top: `${props.position.y}px`,
left: `${props.position.x}px`,
}));
const handleAction = (item: MenuItem) => {
console.log(`[ContextMenu] handleAction called for item:`, JSON.stringify(item)); // + Log item
if (!item.disabled && !item.isSeparator) {
console.log(`[ContextMenu] Inside handleAction, props.targetId is:`, props.targetId); // ++ Log prop value before emit
const payload = { action: item.action, targetId: props.targetId };
console.log(`[ContextMenu] Emitting menu-action with payload:`, JSON.stringify(payload)); // + Log emit payload
emit('menu-action', payload);
emit('close'); // 点击后自动关闭
}
};
// 点击菜单外部时,也应该关闭,这通常在父组件中处理 document click listener
// 但这里也添加一个遮罩层点击关闭
const handleOverlayClick = () => {
emit('close');
};
</script>
<template>
<div
v-if="visible"
class="fixed inset-0 z-40"
@click.self="handleOverlayClick"
@contextmenu.prevent
>
<div
class="fixed bg-background border border-border/50 shadow-xl rounded-lg py-1.5 z-50 min-w-[180px]"
:style="menuStyle"
@click.stop
>
<ul class="list-none p-0 m-0">
<template v-for="(item, index) in items" :key="index">
<li v-if="item.isSeparator" class="border-t border-border/50 my-1 mx-1"></li>
<li
v-else
class="group px-4 py-1.5 flex items-center text-sm transition-colors duration-150 rounded-md mx-1"
:class="[
item.disabled
? 'text-text-secondary opacity-50 cursor-not-allowed'
: item.isDanger
? 'text-error hover:bg-error/10 cursor-pointer'
: 'text-foreground hover:bg-primary/10 hover:text-primary cursor-pointer',
]"
@click="handleAction(item)"
>
<!-- 移除了图标 -->
<span>{{ t(item.label, item.label) }}</span> <!-- 使用 i18n -->
</li>
</template>
</ul>
</div>
</div>
</template>
<style scoped>
/* 可以添加一些额外的样式,如果需要的话 */
</style>