Enhance TemplateEditor and TemplatePreview Components with Layout Improvements

- Added minWidth property to the TemplateEditor component for better layout control.
- Introduced a responsive toolbar in the TemplatePreview component, utilizing Popover for improved UI on smaller screens.
- Implemented a ResizeObserver to dynamically adjust toolbar settings based on available width, enhancing user experience.
- Refactored toolbar content handling to streamline button interactions and improve accessibility.
This commit is contained in:
Tom Butcher 2026-09-07 01:20:28 +01:00
parent ae1194efb9
commit 7df004ac47
2 changed files with 103 additions and 61 deletions

View File

@ -110,6 +110,7 @@ const TemplateEditor = ({
const [previewError, setPreviewError] = useState(false)
const [errorLines, setErrorLines] = useState([])
const [formatLoading, setFormatLoading] = useState(false)
//const isMobile = useMediaQuery({ maxWidth: 768 })
const handlePreviewMessage = useCallback((message, isError) => {
@ -256,7 +257,8 @@ const TemplateEditor = ({
width: '100%',
height: '100%',
flex: '1 1 auto',
minHeight: 0
minHeight: 0,
minWidth: 0
}}
useFormItem={false}
name={'content'}

View File

@ -7,7 +7,7 @@ import {
useCallback
} from 'react'
import PropTypes from 'prop-types'
import { Flex, Button, Input, Select, Card } from 'antd'
import { Flex, Button, Input, Select, Card, Popover } from 'antd'
import PlusIcon from '../../Icons/PlusIcon.jsx'
import MinusIcon from '../../Icons/MinusIcon.jsx'
import InfoCircleIcon from '../../Icons/InfoCircleIcon.jsx'
@ -18,7 +18,7 @@ import PDFViewer from './PDFViewer.jsx'
import ScrollBox from './ScrollBox.jsx'
import { ApiServerContext } from '../context/ApiServerContext.jsx'
import ProgressDisplay from './ProgressDisplay.jsx'
import { CaretDownFilled } from '@ant-design/icons'
const noop = () => {}
const TemplatePreview = ({
@ -56,6 +56,27 @@ const TemplatePreview = ({
height: 'auto'
})
const toolbarRef = useRef(null)
const [usePopoverSettings, setUsePopoverSettings] = useState(false)
useLayoutEffect(() => {
const toolbar = toolbarRef.current
if (!toolbar) return undefined
const updateLayout = () => {
const { width, height } = toolbar.getBoundingClientRect()
console.log('Preview card size', { width, height })
setUsePopoverSettings(width < 620)
}
updateLayout()
const observer = new ResizeObserver(updateLayout)
observer.observe(toolbar)
return () => observer.disconnect()
}, [])
const applyIframeContentSize = useCallback(() => {
const iframe = iframeRef.current
const doc = iframe?.contentDocument
@ -474,9 +495,70 @@ const TemplatePreview = ({
const showProgressOverlay = previewType != 'HTML' && downloadProgress != null
const toolbarContent = (
<>
<Button
icon={
panMode ? (
<PanFilledIcon style={{ color: 'var(--color-primary)' }} />
) : (
<PanIcon />
)
}
disabled={loading || reloadLoading}
onClick={() => {
setPanMode((prev) => !prev)
}}
/>
<Button
icon={<PlusIcon />}
onClick={() => {
setPreviewScale((prev) => prev + 0.05)
}}
disabled={loading || reloadLoading}
/>
<Button
readOnly={true}
style={{ width: '65px' }}
disabled={loading || reloadLoading}
onClick={() => {
setPreviewScale(1)
}}
>
{previewScale.toFixed(2)}x
</Button>
<Button
icon={<MinusIcon />}
onClick={() => {
setPreviewScale((prev) => Math.max(0.1, prev - 0.05))
}}
disabled={loading || reloadLoading}
/>
{showPreviewSwitch == true ? (
<Select
options={[
{ value: 'HTML', label: 'HTML' },
{ value: 'PDF', label: 'PDF' }
]}
style
loading={(loading || reloadLoading) && !usePopoverSettings}
disabled={loading || reloadLoading}
value={previewType}
onChange={(value) => {
if (value == 'PDF') {
clearIframeContents()
setPDFBlob(null)
}
setPreviewType(value)
}}
/>
) : null}
</>
)
return (
<Flex vertical gap={'middle'} style={{ height: '100%' }}>
<Flex gap={'small'}>
<Flex gap={'small'} ref={toolbarRef}>
{showTestObject == true ? (
<>
{documentTemplate?.objectType ? (
@ -503,63 +585,21 @@ const TemplatePreview = ({
/>
</>
) : null}
<Button
icon={
panMode ? (
<PanFilledIcon style={{ color: 'var(--color-primary)' }} />
) : (
<PanIcon />
)
}
disabled={loading || reloadLoading}
onClick={() => {
setPanMode((prev) => !prev)
}}
/>
<Button
icon={<PlusIcon />}
onClick={() => {
setPreviewScale((prev) => prev + 0.05)
}}
disabled={loading || reloadLoading}
/>
<Button
icon={<MinusIcon />}
onClick={() => {
setPreviewScale((prev) => Math.max(0.1, prev - 0.05))
}}
disabled={loading || reloadLoading}
/>
<Button
readOnly={true}
style={{ width: '65px' }}
disabled={loading || reloadLoading}
onClick={() => {
setPreviewScale(1)
}}
>
{previewScale.toFixed(2)}x
</Button>
{showPreviewSwitch == true ? (
<Select
options={[
{ value: 'HTML', label: 'HTML' },
{ value: 'PDF', label: 'PDF' }
]}
style
loading={loading || reloadLoading}
disabled={loading || reloadLoading}
value={previewType}
onChange={(value) => {
if (value == 'PDF') {
clearIframeContents()
setPDFBlob(null)
}
setPreviewType(value)
}}
/>
) : null}
{!usePopoverSettings ? (
toolbarContent
) : (
<Popover
content={<Flex gap={'small'}>{toolbarContent}</Flex>}
trigger={['hover', 'click']}
placement='bottomRight'
arrow={false}
>
<Button
icon={<CaretDownFilled />}
loading={loading || reloadLoading}
/>
</Popover>
)}
</Flex>
<div