Compare commits

...

2 commits

Author SHA1 Message Date
Julie Blanc
ccdd9bda05 correction scroll preview 2026-03-08 08:51:22 +01:00
Julie Blanc
c3c9de2ca2 add zoom composant 2026-03-08 08:44:39 +01:00
3 changed files with 87 additions and 9 deletions

View file

@ -6,6 +6,7 @@ import ElementPopup from './components/ElementPopup.vue';
import PreviewLoader from './components/PreviewLoader.vue';
import SaveButton from './components/SaveButton.vue';
import PrintButton from './components/PrintButton.vue';
import ZoomControls from './components/ui/ZoomControls.vue';
import { onMounted, ref, computed, provide } from 'vue';
import { useStylesheetStore } from './stores/stylesheet';
import { useNarrativeStore } from './stores/narrative';
@ -73,6 +74,10 @@ const { handleKeyboardShortcut, isMac } = useKeyboardShortcuts({
// Attach keyboard shortcut handler to renderer
setKeyboardShortcutHandler(handleKeyboardShortcut);
// 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)
@ -99,11 +104,13 @@ onMounted(async () => {
ref="previewFrame1"
class="preview-frame"
:class="{ shifted: activeTab.length > 0 }"
:style="zoomStyle"
></iframe>
<iframe
ref="previewFrame2"
class="preview-frame"
:class="{ shifted: activeTab.length > 0 }"
:style="zoomStyle"
></iframe>
<PreviewLoader :isLoading="isTransitioning" :shifted="activeTab.length > 0" />
@ -124,6 +131,8 @@ onMounted(async () => {
-->
<ZoomControls ref="zoomControls" />
<div id="group-btn">
<SaveButton />
<PrintButton :printPreview="printPreview" />
@ -139,17 +148,15 @@ onMounted(async () => {
width: 100vw;
height: 100vh;
border: none;
margin-left: 0;
transform: scale(1) translateY(0);
height: 100vh;
transition: all 0.2s ease-in-out var(--curve);
transform-origin: top center;
}
.preview-frame.shifted {
/* .preview-frame.shifted {
margin-left: 17.55rem;
transform: scale(0.65) translateY(-40vh);
height: 155vh;
}
} */
.preview-frame:nth-of-type(1) {
z-index: 1;
@ -164,7 +171,7 @@ onMounted(async () => {
.print-btn {
position: fixed;
bottom: 2rem;
right: 2rem;
left: 2rem;
width: 3.5rem;
height: 3.5rem;
border-radius: 50%;

View file

@ -195,7 +195,7 @@
</template>
<script setup>
import { ref, computed, watch, onMounted, inject } from 'vue';
import { ref, computed, watch, onMounted, inject, nextTick } from 'vue';
import bookIcon from '/assets/svg/book.svg?raw';
import { useStylesheetStore } from '../../stores/stylesheet';
import { useDebounce } from '../../composables/useDebounce';
@ -518,7 +518,7 @@ const syncFromStore = () => {
(rightPageMatch && rightPageMatch[0].includes('string(title)'));
runningTitle.value = hasRunningTitle;
} finally {
isUpdatingFromStore = false;
nextTick(() => { isUpdatingFromStore = false; });
}
};

View file

@ -0,0 +1,71 @@
<template>
<div class="zoom-controls">
<button @click="zoomOut" title="Dézoomer"></button>
<button @click="zoomReset" title="Réinitialiser le zoom">{{ Math.round(zoomLevel * 100) }}%</button>
<button @click="zoomIn" title="Zoomer">+</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
const zoomLevel = ref(1);
const zoomIn = () => { triggerZoom(); zoomLevel.value = Math.min(zoomLevel.value + 0.1, 3); };
const zoomOut = () => { triggerZoom(); zoomLevel.value = Math.max(zoomLevel.value - 0.1, 0.2); };
const zoomReset = () => { triggerZoom(); zoomLevel.value = 1; };
const isZooming = ref(false);
let zoomTimer = null;
const triggerZoom = () => {
isZooming.value = true;
clearTimeout(zoomTimer);
zoomTimer = setTimeout(() => { isZooming.value = false; }, 350);
};
const zoomStyle = computed(() => ({
transform: `scale(${zoomLevel.value})`,
height: `${100 / zoomLevel.value}vh`,
transition: isZooming.value ? 'transform 0.3s ease' : 'none',
}));
defineExpose({ zoomStyle });
</script>
<style scoped>
.zoom-controls {
position: fixed;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 0;
z-index: 1000;
background: var(--color-interface-100, #fff);
border: 1px solid var(--color-interface-200, #ddd);
border-radius: 6px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}
.zoom-controls button {
background: none;
border: none;
padding: 0.4rem 0.7rem;
font-size: 0.875rem;
cursor: pointer;
color: var(--color-interface-800, #333);
min-width: 2.5rem;
text-align: center;
}
.zoom-controls button:hover {
background: var(--color-interface-200, #eee);
}
.zoom-controls button:not(:last-child) {
border-right: 1px solid var(--color-interface-200, #ddd);
}
</style>