Files
social-graph/frontend/src/components/GraphCanvasContextMenu.vue
T
gitrusprusandCursor 986d36ff51 Improve graph/map UX and move contact editing to dedicated pages.
Add viewport controls, collapsible panels with persisted state, filters modal, and refined context menus; preserve map layout on navigation and let contacts be edited with relations on /contacts/:id instead of list modals.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 15:15:45 +03:00

105 lines
2.1 KiB
Vue

<template>
<Teleport to="body">
<div
v-if="open"
class="graph-node-menu-overlay"
@click="close"
@contextmenu.prevent="close"
/>
<div
v-if="open"
class="graph-node-menu"
:style="{ left: `${x}px`, top: `${y}px` }"
role="menu"
@click.stop
@contextmenu.prevent
>
<button
v-for="item in actions"
:key="item.id"
type="button"
class="graph-node-menu__item"
role="menuitem"
@click="onSelect(item.id)"
>
{{ item.label }}
</button>
</div>
</Teleport>
</template>
<script setup>
import { onMounted, onUnmounted, watch } from 'vue'
const props = defineProps({
open: { type: Boolean, default: false },
x: { type: Number, default: 0 },
y: { type: Number, default: 0 },
actions: {
type: Array,
default: () => [{ id: 'create-contact', label: 'Добавить контакт' }],
},
})
const emit = defineEmits(['close', 'create-contact', 'select'])
function close() {
emit('close')
}
function onSelect(id) {
emit('select', id)
if (id === 'create-contact') emit('create-contact')
close()
}
function onKeyDown(event) {
if (event.key === 'Escape' && props.open) close()
}
watch(() => props.open, (isOpen) => {
if (isOpen) window.addEventListener('keydown', onKeyDown)
else window.removeEventListener('keydown', onKeyDown)
})
onMounted(() => {
if (props.open) window.addEventListener('keydown', onKeyDown)
})
onUnmounted(() => {
window.removeEventListener('keydown', onKeyDown)
})
</script>
<style scoped>
.graph-node-menu-overlay {
position: fixed;
inset: 0;
z-index: 900;
}
.graph-node-menu {
position: fixed;
z-index: 901;
min-width: 180px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
box-shadow: var(--shadow);
padding: 6px 0;
}
.graph-node-menu__item {
display: block;
width: 100%;
text-align: left;
padding: 8px 14px;
font-size: 13px;
color: var(--text);
background: transparent;
border: none;
cursor: pointer;
}
.graph-node-menu__item:hover {
background: var(--accent-dim);
}
</style>