add cmd+scroll zooming to template builder

This commit is contained in:
Alex Turchyn
2026-06-02 19:34:18 +03:00
committed by Pete Matsyburka
parent 344a3ce198
commit dd6516fd11
4 changed files with 89 additions and 13 deletions
+72 -4
View File
@@ -355,12 +355,17 @@
</div>
<div
id="pages_container"
class="w-full overflow-x-hidden mt-0.5 pt-0.5"
:class="isMobile ? 'overflow-y-auto' : 'overflow-y-hidden md:overflow-y-auto'"
ref="pagesContainer"
class="w-full mt-0.5 pt-0.5"
:class="[
isMobile ? 'overflow-y-auto' : 'overflow-y-hidden md:overflow-y-auto',
zoomLevel > 1 ? 'overflow-x-auto' : 'overflow-x-hidden'
]"
>
<div
ref="documents"
class="pr-3.5 pl-0.5"
:style="zoomLevel > 1 ? { width: `${zoomLevel * 100}%` } : null"
>
<template v-if="!sortedDocuments.length && (withUploadButton || withAddPageButton)">
<Dropzone
@@ -633,6 +638,39 @@
</div>
</div>
</Transition>
<Transition
enter-active-class="transition-all duration-200 ease-out"
enter-from-class="translate-y-4 opacity-0"
enter-to-class="translate-y-0 opacity-100"
leave-active-class="transition-all duration-200 ease-in"
leave-from-class="translate-y-0 opacity-100"
leave-to-class="translate-y-4 opacity-0"
>
<div
v-if="zoomLevel > 1"
class="sticky bottom-0 z-40 pointer-events-none"
>
<div class="absolute left-0 right-0 bottom-4 flex justify-center">
<div class="join shadow pointer-events-auto">
<span class="join-item bg-base-content text-white pl-4 pr-3 h-9 inline-flex items-center text-sm font-semibold cursor-default">
{{ Math.round(zoomLevel * 100) }}%
</span>
<div
class="tooltip tooltip-top"
:data-tip="t('reset_zoom')"
>
<button
type="button"
class="join-item bg-base-content text-white h-9 pl-2 pr-3 inline-flex items-center justify-center cursor-pointer hover:opacity-90 border-l border-white/20"
@click="zoomLevel = 1"
>
<IconX class="w-5 h-5" />
</button>
</div>
</div>
</div>
</div>
</Transition>
<div
id="docuseal_modal_container"
class="modal-container"
@@ -664,7 +702,7 @@ import DocumentControls from './controls'
import MobileFields from './mobile_fields'
import FieldSubmitter from './field_submitter'
import RevisionsModal from './revisions_modal'
import { IconPlus, IconUsersPlus, IconDeviceFloppy, IconChevronDown, IconEye, IconWritingSign, IconInnerShadowTop, IconInfoCircle, IconAdjustments, IconDownload, IconHistory } from '@tabler/icons-vue'
import { IconPlus, IconUsersPlus, IconDeviceFloppy, IconChevronDown, IconEye, IconWritingSign, IconInnerShadowTop, IconInfoCircle, IconAdjustments, IconDownload, IconHistory, IconX } from '@tabler/icons-vue'
import { v4 } from 'uuid'
import { ref, computed, toRaw, defineAsyncComponent } from 'vue'
import * as i18n from './i18n'
@@ -706,6 +744,7 @@ export default {
IconEye,
IconHistory,
IconDeviceFloppy,
IconX,
RevisionsModal
},
provide () {
@@ -1063,7 +1102,8 @@ export default {
isMathLoaded: false,
isRevisionsModalOpen: false,
revisions: [],
beforeRevisionSnapshot: null
beforeRevisionSnapshot: null,
zoomLevel: 1
}
},
computed: {
@@ -1313,6 +1353,8 @@ export default {
this.pendingFieldAttachmentUuids.push(item.attachment_uuid)
}
})
this.$refs.pagesContainer.addEventListener('wheel', this.onPagesWheel, { passive: false })
},
unmounted () {
document.removeEventListener('keyup', this.onKeyUp)
@@ -1320,6 +1362,8 @@ export default {
window.removeEventListener('resize', this.onWindowResize)
window.removeEventListener('dragleave', this.onWindowDragLeave)
this.$refs.pagesContainer.removeEventListener('wheel', this.onPagesWheel)
},
beforeUpdate () {
this.documentRefs = []
@@ -2018,6 +2062,30 @@ export default {
this.isBreakpointLg = this.$el.getRootNode().querySelector('div[data-v-app]').offsetWidth < breakpointLg
},
onPagesWheel (event) {
if (!event.ctrlKey && !event.metaKey) return
event.preventDefault()
const oldZoom = this.zoomLevel
const nextZoom = Math.max(1, Math.min(3, oldZoom - event.deltaY * 0.002))
if (nextZoom === oldZoom) return
const rect = this.$refs.pagesContainer.getBoundingClientRect()
const cursorX = event.clientX - rect.left
const cursorY = event.clientY - rect.top
const ratio = nextZoom / oldZoom
const nextScrollLeft = (this.$refs.pagesContainer.scrollLeft + cursorX) * ratio - cursorX
const nextScrollTop = (this.$refs.pagesContainer.scrollTop + cursorY) * ratio - cursorY
this.zoomLevel = nextZoom
this.$nextTick(() => {
this.$refs.pagesContainer.scrollLeft = nextScrollLeft
this.$refs.pagesContainer.scrollTop = nextScrollTop
})
},
setDocumentRefs (el) {
if (el) {
this.documentRefs.push(el)