diff --git a/app/templates/local_workspace.html b/app/templates/local_workspace.html
index 9498e88..7beba69 100644
--- a/app/templates/local_workspace.html
+++ b/app/templates/local_workspace.html
@@ -1257,28 +1257,41 @@ document.addEventListener('alpine:init', function() {
// ── Context menu ──
onContextMenu(ev) {
- // Find closest element with data-ws-id (works on all views)
var el = ev.target.closest('[data-ws-id]');
if (!el) { this.ctxMenu.visible = false; return; }
var id = parseInt(el.getAttribute('data-ws-id'));
if (!id) { this.ctxMenu.visible = false; return; }
- // Find node in tree
var node = this._findNodeById(this.displayTree, id);
if (!node) { this.ctxMenu.visible = false; return; }
this.ctxMenu = {
visible: true,
- x: Math.min(ev.clientX, window.innerWidth - 200),
- y: Math.min(ev.clientY, window.innerHeight - 300),
+ x: ev.clientX,
+ y: ev.clientY,
node: node,
tags: [...(node.tags||[])]
};
this.ctxTagAdding = false;
this.ctxTagExistingOpen = false;
this.ctxNewTagColor = '#787774';
- // Load available tags (not already on the item)
+ // Load available tags
this.ctxAvailTags = (this.workspaceTags || []).filter(function(t) {
return !(node.tags||[]).some(function(nt) { return nt.id === t.id; });
});
+ // Reposition after DOM update
+ var self = this;
+ self.$nextTick(function() {
+ var menu = self.$el.querySelector('.ctx-menu');
+ if (!menu) return;
+ var rect = menu.getBoundingClientRect();
+ var x = self.ctxMenu.x;
+ var y = self.ctxMenu.y;
+ if (x + rect.width > window.innerWidth - 4) x = window.innerWidth - rect.width - 4;
+ if (y + rect.height > window.innerHeight - 4) y = window.innerHeight - rect.height - 4;
+ if (x < 4) x = 4;
+ if (y < 4) y = 4;
+ self.ctxMenu.x = x;
+ self.ctxMenu.y = y;
+ });
},
ctxAddExistingTag(tag) {