diff --git a/public/assets/css/src/_variables.scss b/public/assets/css/src/_variables.scss
index 43bb561..c632964 100644
--- a/public/assets/css/src/_variables.scss
+++ b/public/assets/css/src/_variables.scss
@@ -4,6 +4,8 @@
--color-browngray-200: #d0c4ba;
--color-browngray-300: #b5a9a1;
+ --color-page-highlight: #ff8a50;
+
--border-radius: 0.2rem;
--space-xs: 0.5rem;
diff --git a/src/App.vue b/src/App.vue
index 81b2d0f..ba2b2f1 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -19,7 +19,9 @@ provide('activeTab', activeTab);
// Page interaction state
const hoveredPage = ref(null);
+const selectedPages = ref([]); // Pages with active border (when popup is open)
const EDGE_THRESHOLD = 30; // px from edge to trigger hover
+const PAGE_HIGHLIGHT_COLOR = '#ff8a50';
let savedScrollPercentage = 0;
const currentFrameIndex = ref(1); // 1 or 2, which iframe is currently visible
@@ -51,6 +53,15 @@ const isNearPageEdge = (pageElement, mouseX, mouseY) => {
);
};
+// Get all pages using the same template as the given page
+const getPagesWithSameTemplate = (page, doc) => {
+ const pageType = page.getAttribute('data-page-type') || 'default';
+ const allPages = doc.querySelectorAll('.pagedjs_page');
+ return Array.from(allPages).filter(
+ (p) => (p.getAttribute('data-page-type') || 'default') === pageType
+ );
+};
+
// Handle mouse movement in iframe
const handleIframeMouseMove = (event) => {
const pages = event.target.ownerDocument.querySelectorAll('.pagedjs_page');
@@ -65,20 +76,28 @@ const handleIframeMouseMove = (event) => {
// Update hover state
if (foundPage !== hoveredPage.value) {
- // Remove highlight from previous page
- if (hoveredPage.value) {
+ // Remove highlight from previous page (only if not in selectedPages)
+ if (hoveredPage.value && !selectedPages.value.includes(hoveredPage.value)) {
hoveredPage.value.style.outline = '';
}
- // Add highlight to new page
- if (foundPage) {
- foundPage.style.outline = '2px solid rgba(97, 175, 239, 0.3)';
+ // Add highlight to new page (only if not already selected)
+ if (foundPage && !selectedPages.value.includes(foundPage)) {
+ foundPage.style.outline = `2px solid ${PAGE_HIGHLIGHT_COLOR}50`;
}
hoveredPage.value = foundPage;
}
};
+// Clear selection highlight from all selected pages
+const clearSelectedPages = () => {
+ selectedPages.value.forEach((page) => {
+ page.style.outline = '';
+ });
+ selectedPages.value = [];
+};
+
// Handle click in iframe
const handleIframeClick = (event) => {
const element = event.target;
@@ -86,7 +105,19 @@ const handleIframeClick = (event) => {
// Check if clicking near a page edge
if (hoveredPage.value) {
event.stopPropagation();
- pagePopup.value.open(hoveredPage.value, event);
+
+ // Clear previous selection
+ clearSelectedPages();
+
+ // Get all pages with same template and highlight them
+ const doc = event.target.ownerDocument;
+ const sameTemplatePages = getPagesWithSameTemplate(hoveredPage.value, doc);
+ sameTemplatePages.forEach((page) => {
+ page.style.outline = `2px solid ${PAGE_HIGHLIGHT_COLOR}`;
+ });
+ selectedPages.value = sameTemplatePages;
+
+ pagePopup.value.open(hoveredPage.value, event, sameTemplatePages.length);
elementPopup.value.close();
return;
}
@@ -94,15 +125,22 @@ const handleIframeClick = (event) => {
// Only show popup for elements inside the page template
const isInsidePage = element.closest('.pagedjs_page');
if (!isInsidePage) {
+ clearSelectedPages();
elementPopup.value.close();
pagePopup.value.close();
return;
}
+ clearSelectedPages();
elementPopup.value.handleIframeClick(event);
pagePopup.value.close();
};
+// Expose clearSelectedPages for PagePopup to call when closing
+const handlePagePopupClose = () => {
+ clearSelectedPages();
+};
+
const renderPreview = async (shouldReloadFromFile = false) => {
if (isTransitioning.value) return;
isTransitioning.value = true;
@@ -228,7 +266,7 @@ onMounted(() => renderPreview(true));
-
+