feat: refactor popups with shared positioning and CSS tooltips

- Add usePopupPosition composable for smart popup positioning
  (bottom-right → bottom-left → top-right → top-left fallback)
- Refactor ElementPopup with complete controls matching mockup
- Add stylesheet sync: popups initialize from and watch store changes
- Add click-to-close behavior: clicking another element closes popup
- Add CSS property tooltips on all form labels (editor panel + popups)
  with dotted underline and monospace code tooltip on hover
- Add field--view-only class and disabled attribute on locked fields

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
isUnknown 2025-12-05 18:21:54 +01:00
parent 25ef4685c1
commit cf1dadb1b3
10 changed files with 1178 additions and 159 deletions

View file

@ -0,0 +1,52 @@
export function usePopupPosition(popupWidth, popupHeight) {
const OFFSET = 10; // Distance from cursor
const calculatePosition = (event) => {
// Get cursor position relative to viewport
const cursorX = event.clientX;
const cursorY = event.clientY;
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
let x, y;
// Try bottom-right
if (
cursorX + OFFSET + popupWidth <= viewportWidth &&
cursorY + OFFSET + popupHeight <= viewportHeight
) {
x = cursorX + OFFSET;
y = cursorY + OFFSET;
}
// Try bottom-left
else if (
cursorX - OFFSET - popupWidth >= 0 &&
cursorY + OFFSET + popupHeight <= viewportHeight
) {
x = cursorX - OFFSET - popupWidth;
y = cursorY + OFFSET;
}
// Try top-right
else if (
cursorX + OFFSET + popupWidth <= viewportWidth &&
cursorY - OFFSET - popupHeight >= 0
) {
x = cursorX + OFFSET;
y = cursorY - OFFSET - popupHeight;
}
// Try top-left (fallback)
else {
x = cursorX - OFFSET - popupWidth;
y = cursorY - OFFSET - popupHeight;
// Ensure it doesn't go off-screen
x = Math.max(10, x);
y = Math.max(10, y);
}
return { x, y };
};
return { calculatePosition };
}