diff --git a/src/App.vue b/src/App.vue index 1b8746a..2df8f57 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,6 +2,7 @@ import PagedJsWrapper from './components/PagedJsWrapper.vue'; import EditorPanel from './components/editor/EditorPanel.vue'; import ElementPopup from './components/ElementPopup.vue'; +import PagePopup from './components/PagePopup.vue'; import PreviewLoader from './components/PreviewLoader.vue'; import { onMounted, ref, watch, computed, provide } from 'vue'; import { useStylesheetStore } from './stores/stylesheet'; @@ -11,10 +12,15 @@ const stylesheetStore = useStylesheetStore(); const previewFrame1 = ref(null); const previewFrame2 = ref(null); const elementPopup = ref(null); +const pagePopup = ref(null); const activeTab = ref(''); provide('activeTab', activeTab); +// Page interaction state +const hoveredPage = ref(null); +const EDGE_THRESHOLD = 30; // px from edge to trigger hover + let savedScrollPercentage = 0; const currentFrameIndex = ref(1); // 1 or 2, which iframe is currently visible const isTransitioning = ref(false); @@ -25,6 +31,77 @@ const activeFrame = computed(() => { : previewFrame2.value; }); +// Check if mouse position is near the edges of a page element +const isNearPageEdge = (pageElement, mouseX, mouseY) => { + const rect = pageElement.getBoundingClientRect(); + + const nearLeft = mouseX >= rect.left && mouseX <= rect.left + EDGE_THRESHOLD; + const nearRight = mouseX >= rect.right - EDGE_THRESHOLD && mouseX <= rect.right; + const nearTop = mouseY >= rect.top && mouseY <= rect.top + EDGE_THRESHOLD; + const nearBottom = mouseY >= rect.bottom - EDGE_THRESHOLD && mouseY <= rect.bottom; + + const inHorizontalRange = mouseY >= rect.top && mouseY <= rect.bottom; + const inVerticalRange = mouseX >= rect.left && mouseX <= rect.right; + + return ( + (nearLeft && inHorizontalRange) || + (nearRight && inHorizontalRange) || + (nearTop && inVerticalRange) || + (nearBottom && inVerticalRange) + ); +}; + +// Handle mouse movement in iframe +const handleIframeMouseMove = (event) => { + const pages = event.target.ownerDocument.querySelectorAll('.pagedjs_page'); + let foundPage = null; + + for (const page of pages) { + if (isNearPageEdge(page, event.clientX, event.clientY)) { + foundPage = page; + break; + } + } + + // Update hover state + if (foundPage !== hoveredPage.value) { + // Remove highlight from previous page + if (hoveredPage.value) { + hoveredPage.value.style.outline = ''; + } + + // Add highlight to new page + if (foundPage) { + foundPage.style.outline = '2px solid rgba(97, 175, 239, 0.3)'; + } + + hoveredPage.value = foundPage; + } +}; + +// Handle click in iframe +const handleIframeClick = (event) => { + const element = event.target; + + // Check if clicking near a page edge + if (hoveredPage.value) { + event.stopPropagation(); + pagePopup.value.open(hoveredPage.value); + elementPopup.value.close(); + return; + } + + // Otherwise handle as element click + if (element.tagName === 'BODY' || element.tagName === 'HTML') { + elementPopup.value.close(); + pagePopup.value.close(); + return; + } + + elementPopup.value.handleIframeClick(event); + pagePopup.value.close(); +}; + const renderPreview = async (shouldReloadFromFile = false) => { if (isTransitioning.value) return; isTransitioning.value = true; @@ -73,10 +150,9 @@ const renderPreview = async (shouldReloadFromFile = false) => { `; hiddenFrame.onload = () => { - hiddenFrame.contentDocument.addEventListener( - 'click', - elementPopup.value.handleIframeClick - ); + // Add event listeners for page and element interactions + hiddenFrame.contentDocument.addEventListener('mousemove', handleIframeMouseMove); + hiddenFrame.contentDocument.addEventListener('click', handleIframeClick); // Close Coloris when clicking in the iframe hiddenFrame.contentDocument.addEventListener('click', () => { @@ -151,6 +227,7 @@ onMounted(() => renderPreview(true)); +