refactor: reorganize App.vue by functional domains

- Group variables and functions by domain instead of by type
- Split handleIframeClick into smaller focused functions
- Add clear section comments for better navigation
- Sections: Store, PagedJS config, Iframe preview, Editor panel, Element popup, Lifecycle

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
isUnknown 2025-11-24 18:01:47 +01:00
parent e8298a9fbf
commit 7bc0dad32b

View file

@ -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);
</script>