Enhance TemplatePreview Component with Scaling and Layout Improvements
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit
- Introduced scaleCssSize function to dynamically adjust CSS sizes based on scaling factor. - Added responsive width control for the preview document, improving layout adaptability. - Implemented useLayoutEffect to apply iframe content size based on preview type and width. - Refactored reloadPreview function to simplify parameters and ensure consistent width handling. - Enhanced iframe rendering with scaling transformations for better visual representation.
This commit is contained in:
parent
a590650d80
commit
f01f978ec6
@ -21,6 +21,17 @@ import ProgressDisplay from './ProgressDisplay.jsx'
|
||||
import { CaretDownFilled } from '@ant-design/icons'
|
||||
const noop = () => {}
|
||||
|
||||
const scaleCssSize = (size, scale) => {
|
||||
if (scale === 1 || typeof size !== 'string' || !size.endsWith('px')) {
|
||||
return size
|
||||
}
|
||||
const value = parseFloat(size)
|
||||
if (!Number.isFinite(value)) {
|
||||
return size
|
||||
}
|
||||
return `${Math.ceil(value * scale)}px`
|
||||
}
|
||||
|
||||
const TemplatePreview = ({
|
||||
objectData,
|
||||
documentTemplate,
|
||||
@ -57,6 +68,8 @@ const TemplatePreview = ({
|
||||
const [previewScale, setPreviewScale] = useState(1)
|
||||
const [previewType, setPreviewType] = useState('HTML')
|
||||
const [previewWidth, setPreviewWidth] = useState(defaultPreviewWidth)
|
||||
const previewWidthRef = useRef(previewWidth)
|
||||
previewWidthRef.current = previewWidth
|
||||
const [panMode, setPanMode] = useState(false)
|
||||
const [isPanning, setIsPanning] = useState(false)
|
||||
const panStartRef = useRef({ x: 0, y: 0, scrollLeft: 0, scrollTop: 0 })
|
||||
@ -93,12 +106,43 @@ const TemplatePreview = ({
|
||||
return
|
||||
}
|
||||
|
||||
if (showWidthControl && !doc.querySelector('.previewDocument') && doc.body) {
|
||||
const container = doc.createElement('div')
|
||||
container.className = 'previewContainer'
|
||||
const pages = doc.createElement('div')
|
||||
pages.className = 'previewPages'
|
||||
pages.id = 'pages'
|
||||
const wrapper = doc.createElement('div')
|
||||
wrapper.className = 'previewWrapper'
|
||||
const page = doc.createElement('div')
|
||||
page.className = 'previewDocument documentPage'
|
||||
page.id = 'content'
|
||||
while (doc.body.firstChild) {
|
||||
page.appendChild(doc.body.firstChild)
|
||||
}
|
||||
wrapper.appendChild(page)
|
||||
pages.appendChild(wrapper)
|
||||
container.appendChild(pages)
|
||||
doc.body.appendChild(container)
|
||||
if (!doc.head?.querySelector('style[data-preview-chrome]')) {
|
||||
const styleEl = doc.createElement('style')
|
||||
styleEl.setAttribute('data-preview-chrome', 'true')
|
||||
styleEl.textContent =
|
||||
'.previewContainer{display:flex;justify-content:center;align-items:flex-start;padding:60px;box-sizing:border-box;width:fit-content}.previewPages{display:flex;flex-direction:row;align-items:flex-start;width:fit-content}.previewWrapper{position:relative;flex-shrink:0}.previewDocument{background:#fff;border:1px solid #000;box-shadow:0 0 5px rgba(0,0,0,.2);transform-origin:top left;position:relative;overflow:visible;box-sizing:content-box}'
|
||||
doc.head?.appendChild(styleEl)
|
||||
}
|
||||
}
|
||||
|
||||
const wrappers = doc.querySelectorAll('.previewWrapper')
|
||||
wrappers.forEach((wrapper) => {
|
||||
const page = wrapper.querySelector('.previewDocument')
|
||||
if (!page) {
|
||||
return
|
||||
}
|
||||
if (showWidthControl) {
|
||||
page.style.width = `${previewWidth}px`
|
||||
page.style.maxWidth = `${previewWidth}px`
|
||||
}
|
||||
const pageVisual = page.getBoundingClientRect()
|
||||
if (pageVisual.width <= 0 && pageVisual.height <= 0) {
|
||||
return
|
||||
@ -130,9 +174,7 @@ const TemplatePreview = ({
|
||||
parseFloat(containerStyle.paddingBottom)
|
||||
}
|
||||
|
||||
const contentWidth = showWidthControl
|
||||
? previewWidth
|
||||
: Math.ceil(visual.width + padX)
|
||||
const contentWidth = Math.ceil(visual.width + padX)
|
||||
const contentHeight = Math.ceil(
|
||||
Math.max(visual.height + padY, doc.documentElement.scrollHeight)
|
||||
)
|
||||
@ -192,6 +234,13 @@ const TemplatePreview = ({
|
||||
restoreScrollPosition()
|
||||
}, [iframeSize, restoreScrollPosition])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (previewType != 'HTML') {
|
||||
return
|
||||
}
|
||||
applyIframeContentSize()
|
||||
}, [applyIframeContentSize, previewType, previewWidth])
|
||||
|
||||
const updatePreviewContentHTML = (html) => {
|
||||
const scrollEl = scrollElementRef.current
|
||||
if (scrollEl) {
|
||||
@ -370,7 +419,7 @@ const TemplatePreview = ({
|
||||
)
|
||||
|
||||
const reloadPreview = useCallback(
|
||||
(content, testObject = {}, scale = 1) => {
|
||||
(content, testObject = {}) => {
|
||||
const templateId = currentTemplate?._id
|
||||
if (!templateId) {
|
||||
return
|
||||
@ -382,7 +431,7 @@ const TemplatePreview = ({
|
||||
templateId,
|
||||
content,
|
||||
testObject,
|
||||
scale,
|
||||
1,
|
||||
(result) => {
|
||||
if (requestId !== previewRequestIdRef.current) {
|
||||
return
|
||||
@ -396,14 +445,13 @@ const TemplatePreview = ({
|
||||
}
|
||||
},
|
||||
templateType,
|
||||
showWidthControl ? { width: previewWidth } : {}
|
||||
showWidthControl ? { width: previewWidthRef.current } : {}
|
||||
)
|
||||
},
|
||||
[
|
||||
currentTemplate?._id,
|
||||
fetchTemplatePreview,
|
||||
onPreviewMessage,
|
||||
previewWidth,
|
||||
showWidthControl,
|
||||
templateType
|
||||
]
|
||||
@ -424,7 +472,7 @@ const TemplatePreview = ({
|
||||
|
||||
const timeoutId = window.setTimeout(() => {
|
||||
if (content == null) {
|
||||
reloadPreview(templateContent, objectData, previewScale)
|
||||
reloadPreview(templateContent, objectData)
|
||||
}
|
||||
}, 300)
|
||||
|
||||
@ -435,8 +483,6 @@ const TemplatePreview = ({
|
||||
objectData,
|
||||
templateContent,
|
||||
templateId,
|
||||
previewScale,
|
||||
previewWidth,
|
||||
previewType,
|
||||
reloadPreview,
|
||||
content
|
||||
@ -534,6 +580,8 @@ const TemplatePreview = ({
|
||||
}, [isPanning])
|
||||
|
||||
const showProgressOverlay = previewType != 'HTML' && downloadProgress != null
|
||||
const scaledIframeWidth = scaleCssSize(iframeSize.width, previewScale)
|
||||
const scaledIframeHeight = scaleCssSize(iframeSize.height, previewScale)
|
||||
|
||||
const toolbarContent = (
|
||||
<>
|
||||
@ -707,14 +755,14 @@ const TemplatePreview = ({
|
||||
align='center'
|
||||
style={{
|
||||
minWidth: '100%',
|
||||
width: iframeSize.width,
|
||||
height: iframeSize.height
|
||||
width: scaledIframeWidth,
|
||||
height: scaledIframeHeight
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: iframeSize.width,
|
||||
height: iframeSize.height,
|
||||
width: scaledIframeWidth,
|
||||
height: scaledIframeHeight,
|
||||
cursor: panMode
|
||||
? isPanning
|
||||
? 'grabbing'
|
||||
@ -729,11 +777,14 @@ const TemplatePreview = ({
|
||||
scrolling='no'
|
||||
frameBorder='0'
|
||||
style={{
|
||||
width: '100%',
|
||||
height: iframeSize.height === 'auto' ? 150 : '100%',
|
||||
width:
|
||||
iframeSize.width === '100%' ? '100%' : iframeSize.width,
|
||||
height: iframeSize.height === 'auto' ? 150 : iframeSize.height,
|
||||
display: 'block',
|
||||
border: 0,
|
||||
overflow: 'hidden',
|
||||
transform: `scale(${previewScale})`,
|
||||
transformOrigin: 'top left',
|
||||
pointerEvents: panMode ? 'none' : undefined
|
||||
}}
|
||||
/>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user