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:
parent
e8298a9fbf
commit
7bc0dad32b
1 changed files with 73 additions and 48 deletions
121
src/App.vue
121
src/App.vue
|
|
@ -6,17 +6,14 @@ import ElementPopup from './components/ElementPopup.vue';
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import { useStylesheetStore } from './stores/stylesheet';
|
import { useStylesheetStore } from './stores/stylesheet';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Store
|
||||||
|
// ============================================================================
|
||||||
const stylesheetStore = useStylesheetStore();
|
const stylesheetStore = useStylesheetStore();
|
||||||
|
|
||||||
const previewFrame = ref(null);
|
// ============================================================================
|
||||||
const aboutFontSize = ref(2);
|
// PagedJS configuration
|
||||||
const aboutFontSizeUnit = ref('rem');
|
// ============================================================================
|
||||||
|
|
||||||
const popupVisible = ref(false);
|
|
||||||
const popupPosition = ref({ x: 0, y: 0 });
|
|
||||||
const popupSelector = ref('');
|
|
||||||
|
|
||||||
// PagedJS print rules
|
|
||||||
const printStyles = `
|
const printStyles = `
|
||||||
h2 { break-before: page; }
|
h2 { break-before: page; }
|
||||||
|
|
||||||
|
|
@ -32,6 +29,11 @@ h2 { break-before: page; }
|
||||||
.chapter > h2 { string-set: title content(text); }
|
.chapter > h2 { string-set: title content(text); }
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Iframe preview
|
||||||
|
// ============================================================================
|
||||||
|
const previewFrame = ref(null);
|
||||||
|
|
||||||
const injectStylesToIframe = () => {
|
const injectStylesToIframe = () => {
|
||||||
const iframe = previewFrame.value;
|
const iframe = previewFrame.value;
|
||||||
if (!iframe?.contentDocument) return;
|
if (!iframe?.contentDocument) return;
|
||||||
|
|
@ -45,45 +47,6 @@ const injectStylesToIframe = () => {
|
||||||
styleElement.textContent = stylesheetStore.content;
|
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 renderPreview = async () => {
|
||||||
const iframe = previewFrame.value;
|
const iframe = previewFrame.value;
|
||||||
if (!iframe) return;
|
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);
|
onMounted(renderPreview);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue