diff --git a/src/App.vue b/src/App.vue index b51b2e2..9e417b4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -6,17 +6,14 @@ import ElementPopup from './components/ElementPopup.vue'; import { onMounted, ref, watch } from 'vue'; import { useStylesheetStore } from './stores/stylesheet'; +// ============================================================================ +// Store +// ============================================================================ const stylesheetStore = useStylesheetStore(); -const previewFrame = ref(null); -const aboutFontSize = ref(2); -const aboutFontSizeUnit = ref('rem'); - -const popupVisible = ref(false); -const popupPosition = ref({ x: 0, y: 0 }); -const popupSelector = ref(''); - -// PagedJS print rules +// ============================================================================ +// PagedJS configuration +// ============================================================================ const printStyles = ` h2 { break-before: page; } @@ -32,6 +29,11 @@ h2 { break-before: page; } .chapter > h2 { string-set: title content(text); } `; +// ============================================================================ +// Iframe preview +// ============================================================================ +const previewFrame = ref(null); + const injectStylesToIframe = () => { const iframe = previewFrame.value; if (!iframe?.contentDocument) return; @@ -45,45 +47,6 @@ const injectStylesToIframe = () => { styleElement.textContent = stylesheetStore.content; }; -const handleIframeClick = (event) => { - const element = event.target; - - if (element.tagName === 'BODY' || element.tagName === 'HTML') { - popupVisible.value = false; - return; - } - - const selector = element.id - ? `#${element.id}` - : `.${element.className.split(' ')[0]}`; - - popupSelector.value = selector; - - const rect = element.getBoundingClientRect(); - const iframeRect = previewFrame.value.getBoundingClientRect(); - popupPosition.value = { - x: iframeRect.left + rect.left, - y: iframeRect.top + rect.bottom + 5, - }; - - popupVisible.value = true; -}; - -const closePopup = () => { - popupVisible.value = false; -}; - -watch(aboutFontSize, (newVal) => { - stylesheetStore.updateProperty( - '.about', - 'font-size', - newVal, - aboutFontSizeUnit.value - ); -}); - -watch(() => stylesheetStore.content, injectStylesToIframe); - const renderPreview = async () => { const iframe = previewFrame.value; if (!iframe) return; @@ -114,6 +77,68 @@ const renderPreview = async () => { }; }; +// ============================================================================ +// Editor panel (temporary hardcoded .about selector) +// ============================================================================ +const aboutFontSize = ref(2); +const aboutFontSizeUnit = ref('rem'); + +watch(aboutFontSize, (newVal) => { + stylesheetStore.updateProperty( + '.about', + 'font-size', + newVal, + aboutFontSizeUnit.value + ); +}); + +// ============================================================================ +// Element popup +// ============================================================================ +const popupVisible = ref(false); +const popupPosition = ref({ x: 0, y: 0 }); +const popupSelector = ref(''); + +const getSelectorFromElement = (element) => { + return element.id + ? `#${element.id}` + : `.${element.className.split(' ')[0]}`; +}; + +const calculatePopupPosition = (element) => { + const rect = element.getBoundingClientRect(); + const iframeRect = previewFrame.value.getBoundingClientRect(); + return { + x: iframeRect.left + rect.left, + y: iframeRect.top + rect.bottom + 5, + }; +}; + +const openPopup = (element) => { + popupSelector.value = getSelectorFromElement(element); + popupPosition.value = calculatePopupPosition(element); + popupVisible.value = true; +}; + +const closePopup = () => { + popupVisible.value = false; +}; + +const handleIframeClick = (event) => { + const element = event.target; + + if (element.tagName === 'BODY' || element.tagName === 'HTML') { + closePopup(); + return; + } + + openPopup(element); +}; + +// ============================================================================ +// Lifecycle +// ============================================================================ +watch(() => stylesheetStore.content, injectStylesToIframe); onMounted(renderPreview);