geoproject-app/src/App.vue

208 lines
5.2 KiB
Vue
Raw Normal View History

<script setup>
import PagedJsWrapper from './components/PagedJsWrapper.vue';
import EditorPanel from './components/editor/EditorPanel.vue';
import ElementPopup from './components/ElementPopup.vue';
2026-03-23 11:13:50 +01:00
import ImagePopup from './components/ImagePopup.vue';
// import PagePopup from './components/PagePopup.vue'; // DISABLED: page template styling feature
import PreviewLoader from './components/PreviewLoader.vue';
import SaveButton from './components/SaveButton.vue';
2026-03-06 17:18:04 +01:00
import PrintButton from './components/PrintButton.vue';
2026-03-08 08:44:39 +01:00
import ZoomControls from './components/ui/ZoomControls.vue';
import { onMounted, ref, computed, provide } from 'vue';
import { useStylesheetStore } from './stores/stylesheet';
import { useNarrativeStore } from './stores/narrative';
import { useKeyboardShortcuts } from './composables/useKeyboardShortcuts';
import { useIframeInteractions } from './composables/useIframeInteractions';
import { usePreviewRenderer } from './composables/usePreviewRenderer';
import { usePrintPreview } from './composables/usePrintPreview';
2026-03-09 15:37:05 +01:00
import { useProjectFonts } from './composables/useProjectFonts';
const stylesheetStore = useStylesheetStore();
const narrativeStore = useNarrativeStore();
2026-03-09 15:37:05 +01:00
const { loadFontsFromCss } = useProjectFonts();
feat: implement page numbers, running titles, and smooth iframe transitions Add functional page number and running title toggles with proper positioning for left/right pages. Implement smooth crossfade transitions between iframe reloads to eliminate visual flicker during PagedJS rendering. Page Numbers & Running Titles: - Page numbers toggle: adds counter(page) to @bottom-left (left pages) or @bottom-right (right pages) - Running title toggle: adds string(title) from h2 chapter titles - Combined positioning: both elements appear side-by-side in same margin box - Left pages: "1 Chapter Title" in @bottom-left - Right pages: "Chapter Title 2" in @bottom-right - Automatic CSS rule management: adds/removes @page:left, @page:right, and string-set rules based on checkbox state - Bidirectional sync: checkboxes reflect existing CSS state on load Smooth Iframe Transitions: - Dual iframe system: two iframes alternate as visible/hidden - Crossfade technique: hidden iframe loads new content while visible remains displayed, then smooth 300ms opacity transition - Scroll preservation: saves scroll percentage from visible iframe, restores to hidden iframe after PagedJS render - Collision prevention: isTransitioning flag prevents overlapping renders - Active frame tracking: computed property ensures ElementPopup always references the visible iframe Technical details: - Uses srcdoc to inject HTML with dynamic CSS - Z-index and opacity manipulation for layering - CSS transitions (opacity 0.3s ease-in-out) - Automatic frame swapping after transition completes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 15:27:23 +01:00
const previewFrame1 = ref(null);
const previewFrame2 = ref(null);
const elementPopup = ref(null);
2026-03-23 11:13:50 +01:00
const imagePopup = ref(null);
// const pagePopup = ref(null); // DISABLED: page template styling feature
const activeTab = ref('');
provide('activeTab', activeTab);
// Setup iframe interactions (hover, click, labels)
const {
// hoveredPage, // DISABLED: page template styling feature
// selectedPages, // DISABLED: page template styling feature
hoveredElement,
selectedElement,
handleIframeMouseMove,
handleIframeClick,
// handlePagePopupClose, // DISABLED: page template styling feature
handleElementPopupClose,
2026-03-23 11:13:50 +01:00
handleImagePopupClose,
} = useIframeInteractions({ elementPopup, imagePopup });
// Setup preview renderer with double buffering
const {
renderPreview,
currentFrameIndex,
isTransitioning,
setKeyboardShortcutHandler,
} = usePreviewRenderer({
previewFrame1,
previewFrame2,
stylesheetStore,
narrativeStore,
handleIframeMouseMove,
handleIframeClick,
});
feat: implement page numbers, running titles, and smooth iframe transitions Add functional page number and running title toggles with proper positioning for left/right pages. Implement smooth crossfade transitions between iframe reloads to eliminate visual flicker during PagedJS rendering. Page Numbers & Running Titles: - Page numbers toggle: adds counter(page) to @bottom-left (left pages) or @bottom-right (right pages) - Running title toggle: adds string(title) from h2 chapter titles - Combined positioning: both elements appear side-by-side in same margin box - Left pages: "1 Chapter Title" in @bottom-left - Right pages: "Chapter Title 2" in @bottom-right - Automatic CSS rule management: adds/removes @page:left, @page:right, and string-set rules based on checkbox state - Bidirectional sync: checkboxes reflect existing CSS state on load Smooth Iframe Transitions: - Dual iframe system: two iframes alternate as visible/hidden - Crossfade technique: hidden iframe loads new content while visible remains displayed, then smooth 300ms opacity transition - Scroll preservation: saves scroll percentage from visible iframe, restores to hidden iframe after PagedJS render - Collision prevention: isTransitioning flag prevents overlapping renders - Active frame tracking: computed property ensures ElementPopup always references the visible iframe Technical details: - Uses srcdoc to inject HTML with dynamic CSS - Z-index and opacity manipulation for layering - CSS transitions (opacity 0.3s ease-in-out) - Automatic frame swapping after transition completes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 15:27:23 +01:00
const activeFrame = computed(() => {
return currentFrameIndex.value === 1
? previewFrame1.value
: previewFrame2.value;
feat: implement page numbers, running titles, and smooth iframe transitions Add functional page number and running title toggles with proper positioning for left/right pages. Implement smooth crossfade transitions between iframe reloads to eliminate visual flicker during PagedJS rendering. Page Numbers & Running Titles: - Page numbers toggle: adds counter(page) to @bottom-left (left pages) or @bottom-right (right pages) - Running title toggle: adds string(title) from h2 chapter titles - Combined positioning: both elements appear side-by-side in same margin box - Left pages: "1 Chapter Title" in @bottom-left - Right pages: "Chapter Title 2" in @bottom-right - Automatic CSS rule management: adds/removes @page:left, @page:right, and string-set rules based on checkbox state - Bidirectional sync: checkboxes reflect existing CSS state on load Smooth Iframe Transitions: - Dual iframe system: two iframes alternate as visible/hidden - Crossfade technique: hidden iframe loads new content while visible remains displayed, then smooth 300ms opacity transition - Scroll preservation: saves scroll percentage from visible iframe, restores to hidden iframe after PagedJS render - Collision prevention: isTransitioning flag prevents overlapping renders - Active frame tracking: computed property ensures ElementPopup always references the visible iframe Technical details: - Uses srcdoc to inject HTML with dynamic CSS - Z-index and opacity manipulation for layering - CSS transitions (opacity 0.3s ease-in-out) - Automatic frame swapping after transition completes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 15:27:23 +01:00
});
// Setup print preview
const { printPreview } = usePrintPreview(activeFrame);
// Setup keyboard shortcuts (depends on printPreview)
const { handleKeyboardShortcut, isMac } = useKeyboardShortcuts({
stylesheetStore,
elementPopup,
// pagePopup, // DISABLED: page template styling feature
activeTab,
printPreview,
});
// Attach keyboard shortcut handler to renderer
setKeyboardShortcutHandler(handleKeyboardShortcut);
2026-03-08 08:44:39 +01:00
// Zoom
const zoomControls = ref(null);
const zoomStyle = computed(() => zoomControls.value?.zoomStyle ?? {});
// Lifecycle: Initialize app on mount
onMounted(async () => {
// Load narrative data (narrativeUrl constructed from location, always present)
await narrativeStore.loadNarrative(location.href + '.json');
// Initialize stylesheet with custom CSS
if (narrativeStore.data) {
await stylesheetStore.initializeFromNarrative(narrativeStore.data);
2026-03-09 15:37:05 +01:00
// Pre-load any fonts referenced in the saved CSS so @font-face rules are ready for the preview
await loadFontsFromCss(stylesheetStore.customCss);
}
// Render preview after data is loaded
renderPreview(true);
});
</script>
<template>
<div id="content-source" style="display: none">
<PagedJsWrapper />
</div>
<EditorPanel />
<iframe
ref="previewFrame1"
class="preview-frame"
:class="{ shifted: activeTab.length > 0 }"
2026-03-08 08:44:39 +01:00
:style="zoomStyle"
></iframe>
<iframe
ref="previewFrame2"
class="preview-frame"
:class="{ shifted: activeTab.length > 0 }"
2026-03-08 08:44:39 +01:00
:style="zoomStyle"
></iframe>
<PreviewLoader :isLoading="isTransitioning" :shifted="activeTab.length > 0" />
2026-03-06 17:18:04 +01:00
<ElementPopup
ref="elementPopup"
:iframeRef="activeFrame"
@close="handleElementPopupClose"
/>
2026-03-23 11:13:50 +01:00
<ImagePopup
ref="imagePopup"
@close="handleImagePopupClose"
/>
<!-- DISABLED: page template styling feature
<PagePopup
ref="pagePopup"
:iframeRef="activeFrame"
@close="handlePagePopupClose"
/>
-->
2026-03-06 17:18:04 +01:00
2026-03-08 08:44:39 +01:00
<ZoomControls ref="zoomControls" />
2026-03-09 14:31:56 +01:00
<div id="actions-btn">
2026-03-06 17:18:04 +01:00
<SaveButton />
<PrintButton :printPreview="printPreview" />
</div>
</template>
<style>
feat: implement page numbers, running titles, and smooth iframe transitions Add functional page number and running title toggles with proper positioning for left/right pages. Implement smooth crossfade transitions between iframe reloads to eliminate visual flicker during PagedJS rendering. Page Numbers & Running Titles: - Page numbers toggle: adds counter(page) to @bottom-left (left pages) or @bottom-right (right pages) - Running title toggle: adds string(title) from h2 chapter titles - Combined positioning: both elements appear side-by-side in same margin box - Left pages: "1 Chapter Title" in @bottom-left - Right pages: "Chapter Title 2" in @bottom-right - Automatic CSS rule management: adds/removes @page:left, @page:right, and string-set rules based on checkbox state - Bidirectional sync: checkboxes reflect existing CSS state on load Smooth Iframe Transitions: - Dual iframe system: two iframes alternate as visible/hidden - Crossfade technique: hidden iframe loads new content while visible remains displayed, then smooth 300ms opacity transition - Scroll preservation: saves scroll percentage from visible iframe, restores to hidden iframe after PagedJS render - Collision prevention: isTransitioning flag prevents overlapping renders - Active frame tracking: computed property ensures ElementPopup always references the visible iframe Technical details: - Uses srcdoc to inject HTML with dynamic CSS - Z-index and opacity manipulation for layering - CSS transitions (opacity 0.3s ease-in-out) - Automatic frame swapping after transition completes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 15:27:23 +01:00
.preview-frame {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
border: none;
2026-03-08 08:44:39 +01:00
transform-origin: top center;
}
2026-03-08 08:44:39 +01:00
/* .preview-frame.shifted {
margin-left: 17.55rem;
transform: scale(0.65) translateY(-40vh);
height: 155vh;
2026-03-08 08:44:39 +01:00
} */
feat: implement page numbers, running titles, and smooth iframe transitions Add functional page number and running title toggles with proper positioning for left/right pages. Implement smooth crossfade transitions between iframe reloads to eliminate visual flicker during PagedJS rendering. Page Numbers & Running Titles: - Page numbers toggle: adds counter(page) to @bottom-left (left pages) or @bottom-right (right pages) - Running title toggle: adds string(title) from h2 chapter titles - Combined positioning: both elements appear side-by-side in same margin box - Left pages: "1 Chapter Title" in @bottom-left - Right pages: "Chapter Title 2" in @bottom-right - Automatic CSS rule management: adds/removes @page:left, @page:right, and string-set rules based on checkbox state - Bidirectional sync: checkboxes reflect existing CSS state on load Smooth Iframe Transitions: - Dual iframe system: two iframes alternate as visible/hidden - Crossfade technique: hidden iframe loads new content while visible remains displayed, then smooth 300ms opacity transition - Scroll preservation: saves scroll percentage from visible iframe, restores to hidden iframe after PagedJS render - Collision prevention: isTransitioning flag prevents overlapping renders - Active frame tracking: computed property ensures ElementPopup always references the visible iframe Technical details: - Uses srcdoc to inject HTML with dynamic CSS - Z-index and opacity manipulation for layering - CSS transitions (opacity 0.3s ease-in-out) - Automatic frame swapping after transition completes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 15:27:23 +01:00
.preview-frame:nth-of-type(1) {
z-index: 1;
opacity: 1;
}
.preview-frame:nth-of-type(2) {
z-index: 0;
opacity: 0;
}
/* Hide UI elements when printing */
@media print {
#editor-panel,
#element-popup,
#page-popup,
2026-03-09 14:31:56 +01:00
#actions-btn,
.preview-loader,
.print-btn {
display: none !important;
}
.preview-frame {
position: static !important;
margin-left: 0 !important;
transform: none !important;
width: 100% !important;
height: auto !important;
}
.preview-frame:not(:first-of-type) {
display: none !important;
}
}
</style>