99 lines
3.4 KiB
JavaScript
99 lines
3.4 KiB
JavaScript
import { useEffect, useRef} from 'react'
|
|
import Svg from '../../draft/svg'
|
|
import Defs from '../../draft/defs'
|
|
import Part from './part'
|
|
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch"
|
|
|
|
const Draft = props => {
|
|
const { patternProps, gist, updateGist, app, bgProps={}, fitLayoutPart = false, layoutType="printLayout"} = props
|
|
|
|
let layout = {...props.layout}
|
|
const svgRef = useRef(null);
|
|
|
|
if (!patternProps) return null
|
|
|
|
// Helper method to update part layout and re-calculate width * height
|
|
const updateLayout = (name, config, history=true) => {
|
|
// Start creating new layout
|
|
const newLayout = {...layout}
|
|
newLayout.parts[name] = config
|
|
|
|
// Pattern topLeft and bottomRight
|
|
let topLeft = {x: 0, y: 0}
|
|
let bottomRight = {x: 0, y: 0}
|
|
for (const [pname, part] of Object.entries(patternProps.parts)) {
|
|
if (pname == props.layoutPart && !fitLayoutPart) continue
|
|
let partLayout = newLayout.parts[pname];
|
|
|
|
// Pages part does not have its topLeft and bottomRight set by core since it's added post-draft
|
|
if (partLayout?.tl) {
|
|
// set the pattern extremes
|
|
topLeft.x = Math.min(topLeft.x, partLayout.tl.x)
|
|
topLeft.y = Math.min(topLeft.y, partLayout.tl.y)
|
|
bottomRight.x = Math.max(bottomRight.x, partLayout.br.x)
|
|
bottomRight.y = Math.max(bottomRight.y, partLayout.br.y);
|
|
}
|
|
}
|
|
|
|
newLayout.width = bottomRight.x - topLeft.x
|
|
newLayout.height = bottomRight.y - topLeft.y
|
|
newLayout.bottomRight = bottomRight
|
|
newLayout.topLeft = topLeft
|
|
|
|
if (history) {
|
|
updateGist(['layouts', layoutType], newLayout, history)
|
|
} else {
|
|
// we don't put it in the gist if it shouldn't contribute to history because we need some the data calculated here for rendering purposes on the initial layout, but we don't want to actually save a layout until the user manipulates it
|
|
layout = newLayout
|
|
}
|
|
}
|
|
|
|
|
|
// We need to make sure the `pages` part is at the bottom of the pile
|
|
// so we can drag-drop all parts on top of it.
|
|
// Bottom in SVG means we need to draw it first
|
|
const partList = Object.keys(patternProps.parts)
|
|
|
|
return (
|
|
<div className="my-8 w-11/12 m-auto border-2 border-dotted border-base-content shadow">
|
|
<TransformWrapper
|
|
minScale={0.1}
|
|
centerZoomedOut={true}
|
|
wheel={{ activationKeys: ['Control'] }}
|
|
>
|
|
<TransformComponent>
|
|
<Svg {...patternProps}
|
|
embed={gist.embed}
|
|
ref={svgRef}
|
|
viewBox={layout.topLeft ? `${layout.topLeft.x} ${layout.topLeft.y} ${layout.width} ${layout.height}` : false}
|
|
style={{height: '90vh'}}
|
|
>
|
|
<Defs {...patternProps} />
|
|
<style>{`:root { --pattern-scale: ${gist.scale || 1}}`}</style>
|
|
<g>
|
|
<rect x="0" y="0" width={layout.width} height={layout.height} {...bgProps} />
|
|
{[
|
|
partList.filter(name => name === props.layoutPart),
|
|
partList.filter(name => name !== props.layoutPart),
|
|
].map(list => list.map(name => (
|
|
<Part {...{
|
|
key:name,
|
|
partName: name,
|
|
part: patternProps.parts[name],
|
|
layout,
|
|
app,
|
|
gist,
|
|
updateLayout,
|
|
isLayoutPart: name === props.layoutPart
|
|
}}/>
|
|
)))}
|
|
</g>
|
|
</Svg>
|
|
</TransformComponent>
|
|
</TransformWrapper>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default Draft
|
|
|