diff --git a/public/assets/css/pagedjs-interface.css b/public/assets/css/pagedjs-interface.css index c03eeb7..bcef24a 100644 --- a/public/assets/css/pagedjs-interface.css +++ b/public/assets/css/pagedjs-interface.css @@ -144,54 +144,6 @@ /*--------------------------------------------------------------------------------------*/ } -/* Hover and selection states for pages and elements */ -.page-hovered { - outline: 2px solid #ff8a5050 !important; - cursor: pointer !important; -} - -.page-selected { - outline: 2px solid #ff8a50 !important; -} - -.element-hovered { - outline: 2px solid #7136ff50 !important; - cursor: pointer !important; -} - -.element-selected { - outline: 2px dashed #7136ff !important; - background-color: #7136ff1a !important; -} - -.element-hover-label { - position: absolute; - background: #7136ff; - color: white; - padding: 0.25rem 0.5rem; - border-radius: 4px; - font-size: 0.875rem; - font-weight: 600; - opacity: 0.3; - pointer-events: none; - z-index: 9999; - font-family: sans-serif; -} - -.page-hover-label { - position: absolute; - background: #ff8a50; - color: white; - padding: 0.25rem 0.5rem; - border-radius: 4px; - font-size: 0.875rem; - font-weight: 600; - opacity: 0.3; - pointer-events: none; - z-index: 9999; - font-family: sans-serif; -} - /* Marks (to delete when merge in paged.js) */ .pagedjs_marks-crop { diff --git a/src/App.vue b/src/App.vue index 5d129f6..44ce2a6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -41,11 +41,9 @@ 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 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 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; @@ -67,90 +65,6 @@ const getPagesWithSameTemplate = (page, doc) => { ); }; -// Get selector for element (same logic as ElementPopup) -const getSelectorFromElement = (element) => { - if (element.id) { - return `#${element.id}`; - } - const tagName = element.tagName.toLowerCase(); - // Filter out state classes (element-hovered, element-selected, page-hovered, page-selected) - const classes = Array.from(element.classList).filter( - (cls) => - ![ - 'element-hovered', - 'element-selected', - 'page-hovered', - 'page-selected', - ].includes(cls) - ); - if (classes.length > 0) { - return `${tagName}.${classes[0]}`; - } - return tagName; -}; - -// Create and position element label on hover -const createElementLabel = (element) => { - const doc = element.ownerDocument; - const existingLabel = doc.querySelector('.element-hover-label'); - if (existingLabel) { - existingLabel.remove(); - } - - const rect = element.getBoundingClientRect(); - const scrollTop = doc.documentElement.scrollTop || doc.body.scrollTop; - const scrollLeft = doc.documentElement.scrollLeft || doc.body.scrollLeft; - - const label = doc.createElement('div'); - label.className = 'element-hover-label'; - label.textContent = getSelectorFromElement(element); - label.style.top = `${rect.top + scrollTop - 32}px`; - label.style.left = `${rect.left + scrollLeft}px`; - - doc.body.appendChild(label); - return label; -}; - -// Remove element label -const removeElementLabel = (doc) => { - const label = doc.querySelector('.element-hover-label'); - if (label) { - label.remove(); - } -}; - -// Create and position page label on hover -const createPageLabel = (page) => { - const doc = page.ownerDocument; - const existingLabel = doc.querySelector('.page-hover-label'); - if (existingLabel) { - existingLabel.remove(); - } - - const rect = page.getBoundingClientRect(); - const scrollTop = doc.documentElement.scrollTop || doc.body.scrollTop; - const scrollLeft = doc.documentElement.scrollLeft || doc.body.scrollLeft; - - const templateName = page.getAttribute('data-page-type') || 'default'; - - const label = doc.createElement('div'); - label.className = 'page-hover-label'; - label.textContent = `@page ${templateName}`; - label.style.top = `${rect.top + scrollTop - 32}px`; - label.style.left = `${rect.left + scrollLeft}px`; - - doc.body.appendChild(label); - return label; -}; - -// Remove page label -const removePageLabel = (doc) => { - const label = doc.querySelector('.page-hover-label'); - if (label) { - label.remove(); - } -}; - // Handle mouse movement in iframe const handleIframeMouseMove = (event) => { const pages = event.target.ownerDocument.querySelectorAll('.pagedjs_page'); @@ -168,16 +82,12 @@ const handleIframeMouseMove = (event) => { if (foundPage !== hoveredPage.value) { // Remove highlight from previous page (only if not in selectedPages) if (hoveredPage.value && !selectedPages.value.includes(hoveredPage.value)) { - hoveredPage.value.classList.remove('page-hovered'); + hoveredPage.value.style.outline = ''; } - // Remove previous page label - removePageLabel(event.target.ownerDocument); - // Add highlight to new page (only if not already selected) if (foundPage && !selectedPages.value.includes(foundPage)) { - foundPage.classList.add('page-hovered'); - createPageLabel(foundPage); + foundPage.style.outline = `2px solid ${PAGE_HIGHLIGHT_COLOR}50`; } hoveredPage.value = foundPage; @@ -186,88 +96,46 @@ const handleIframeMouseMove = (event) => { // If not near page edge, check for content element hover if (!foundPage) { const contentElement = getContentElement(event.target); - const doc = event.target.ownerDocument; if (contentElement !== hoveredElement.value) { // Remove highlight from previous element (only if not selected) - if ( - hoveredElement.value && - hoveredElement.value !== selectedElement.value - ) { - hoveredElement.value.classList.remove('element-hovered'); + if (hoveredElement.value && hoveredElement.value !== selectedElement.value) { + hoveredElement.value.style.outline = ''; } - // Remove previous labels - removeElementLabel(doc); - removePageLabel(doc); - // Add highlight to new element (only if not already selected) if (contentElement && contentElement !== selectedElement.value) { - contentElement.classList.add('element-hovered'); - createElementLabel(contentElement); + contentElement.style.outline = `2px dashed ${ELEMENT_HIGHLIGHT_COLOR}`; } hoveredElement.value = contentElement; } } else { // Clear element hover when hovering page edge - if ( - hoveredElement.value && - hoveredElement.value !== selectedElement.value - ) { - hoveredElement.value.classList.remove('element-hovered'); + if (hoveredElement.value && hoveredElement.value !== selectedElement.value) { + hoveredElement.value.style.outline = ''; hoveredElement.value = null; } - // Remove element label when hovering page edge - removeElementLabel(event.target.ownerDocument); } }; // Clear selection highlight from all selected pages const clearSelectedPages = () => { selectedPages.value.forEach((page) => { - page.classList.remove('page-selected'); + page.style.outline = ''; }); selectedPages.value = []; }; // Content elements that can trigger ElementPopup const CONTENT_ELEMENTS = [ - 'P', - 'H1', - 'H2', - 'H3', - 'H4', - 'H5', - 'H6', - 'IMG', - 'FIGURE', - 'FIGCAPTION', - 'UL', - 'OL', - 'LI', - 'BLOCKQUOTE', - 'PRE', - 'CODE', - 'TABLE', - 'THEAD', - 'TBODY', - 'TR', - 'TH', - 'TD', - 'A', - 'SPAN', - 'STRONG', - 'EM', - 'B', - 'I', - 'U', - 'ARTICLE', - 'SECTION', - 'ASIDE', - 'HEADER', - 'FOOTER', - 'NAV', + 'P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', + 'IMG', 'FIGURE', 'FIGCAPTION', + 'UL', 'OL', 'LI', + 'BLOCKQUOTE', 'PRE', 'CODE', + 'TABLE', 'THEAD', 'TBODY', 'TR', 'TH', 'TD', + 'A', 'SPAN', 'STRONG', 'EM', 'B', 'I', 'U', + 'ARTICLE', 'SECTION', 'ASIDE', 'HEADER', 'FOOTER', 'NAV' ]; // Check if element is a content element (or find closest content parent) @@ -285,9 +153,8 @@ const getContentElement = (element) => { // Clear selected element highlight const clearSelectedElement = () => { if (selectedElement.value) { - selectedElement.value.classList.remove('element-selected'); - const doc = selectedElement.value.ownerDocument; - removeElementLabel(doc); + selectedElement.value.style.outline = ''; + selectedElement.value.style.backgroundColor = ''; selectedElement.value = null; } }; @@ -315,14 +182,10 @@ const handleIframeClick = (event) => { const doc = event.target.ownerDocument; const sameTemplatePages = getPagesWithSameTemplate(hoveredPage.value, doc); sameTemplatePages.forEach((page) => { - page.classList.add('page-selected'); + page.style.outline = `2px solid ${PAGE_HIGHLIGHT_COLOR}`; }); selectedPages.value = sameTemplatePages; - // Remove labels when opening popup - removePageLabel(doc); - removeElementLabel(doc); - pagePopup.value.open(hoveredPage.value, event, sameTemplatePages.length); elementPopup.value.close(); return; @@ -351,35 +214,16 @@ const handleIframeClick = (event) => { // Clear page selections clearSelectedPages(); - // If popup is already open and we're clicking another element, close it - if (elementPopup.value.visible) { - clearSelectedElement(); - elementPopup.value.close(); - pagePopup.value.close(); - return; - } - // Clear previous element selection clearSelectedElement(); - // Remove hovered class from the element we're about to select - contentElement.classList.remove('element-hovered'); - - // Clear the hoveredElement ref if it's the same as what we're selecting - if (hoveredElement.value === contentElement) { - hoveredElement.value = null; - } - - // Get document and remove labels when opening popup - const doc = event.target.ownerDocument; - removeElementLabel(doc); - removePageLabel(doc); - // Select the new element selectedElement.value = contentElement; - contentElement.classList.add('element-selected'); + contentElement.style.outline = ''; + contentElement.style.backgroundColor = `${ELEMENT_HIGHLIGHT_COLOR}4D`; // 30% opacity // Get count of similar elements + const doc = event.target.ownerDocument; const count = getSimilarElementsCount(contentElement, doc); elementPopup.value.handleIframeClick(event, contentElement, count); @@ -445,10 +289,7 @@ const renderPreview = async (shouldReloadFromFile = false) => { hiddenFrame.onload = () => { // Add event listeners for page and element interactions - hiddenFrame.contentDocument.addEventListener( - 'mousemove', - handleIframeMouseMove - ); + hiddenFrame.contentDocument.addEventListener('mousemove', handleIframeMouseMove); hiddenFrame.contentDocument.addEventListener('click', handleIframeClick); // Close Coloris when clicking in the iframe @@ -582,26 +423,12 @@ onMounted(() => renderPreview(true)); - - + + @@ -651,9 +478,7 @@ onMounted(() => renderPreview(true)); align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); - transition: - transform 0.2s ease, - box-shadow 0.2s ease; + transition: transform 0.2s ease, box-shadow 0.2s ease; z-index: 1000; } diff --git a/src/components/ElementPopup.vue b/src/components/ElementPopup.vue index a8d9a73..a6ebd79 100644 --- a/src/components/ElementPopup.vue +++ b/src/components/ElementPopup.vue @@ -337,10 +337,8 @@ const getSelectorFromElement = (element) => { // Get tag name const tagName = element.tagName.toLowerCase(); - // Get first class if available (filter out state classes) - const classes = Array.from(element.classList).filter( - (cls) => !['element-hovered', 'element-selected', 'page-hovered', 'page-selected'].includes(cls) - ); + // Get first class if available + const classes = Array.from(element.classList); if (classes.length > 0) { return `${tagName}.${classes[0]}`; }