separate print layout from draft layout. add better buttons
This commit is contained in:
parent
236f35f765
commit
1a65a16e56
16 changed files with 246 additions and 112 deletions
|
@ -362,25 +362,41 @@ export function pctBasedOn(measurement) {
|
|||
|
||||
/** Generates the transform attributes needed for a given part */
|
||||
export const generatePartTransform = (x, y, rotate, flipX, flipY, part) => {
|
||||
const center = {
|
||||
x: part.topLeft.x + (part.bottomRight.x - part.topLeft.x)/2,
|
||||
y: part.topLeft.y + (part.bottomRight.y - part.topLeft.y)/2,
|
||||
|
||||
const transforms = []
|
||||
let xTotal = x || 0;
|
||||
let yTotal = y || 0;
|
||||
let scaleX = 1
|
||||
let scaleY = 1
|
||||
|
||||
if (flipX) {
|
||||
scaleX = -1
|
||||
xTotal += part.topLeft.x * 2 + part.width
|
||||
}
|
||||
if (flipY) {
|
||||
scaleY = -1
|
||||
yTotal += part.topLeft.y * 2 + part.height
|
||||
}
|
||||
|
||||
const transforms = [`translate(${x},${y})`]
|
||||
if (flipX) transforms.push(
|
||||
'scale(-1, 1)',
|
||||
)
|
||||
if (flipY) transforms.push(
|
||||
'scale(1, -1)',
|
||||
)
|
||||
if (rotate) transforms.push(
|
||||
`rotate(${rotate})`
|
||||
if (scaleX + scaleY < 2) {
|
||||
transforms.push(`scale(${scaleX} ${scaleY})`)
|
||||
}
|
||||
|
||||
if (rotate) {
|
||||
const center = {
|
||||
x: part.topLeft.x + part.width/2,
|
||||
y: part.topLeft.y + part.height/2,
|
||||
}
|
||||
|
||||
transforms.push(`rotate(${rotate} ${center.x} ${center.y})`)
|
||||
}
|
||||
|
||||
if (xTotal > 0 || yTotal > 0) transforms.unshift(
|
||||
`translate(${xTotal} ${yTotal})`
|
||||
)
|
||||
|
||||
return {
|
||||
transform: transforms.join(' '),
|
||||
'transform-origin': `${center.x} ${center.y}`
|
||||
// 'transform-origin': `${center.x} ${center.y}`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
export const ClearIconInner = () => <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2M3 12l6.414 6.414a2 2 0 001.414.586H19a2 2 0 002-2V7a2 2 0 00-2-2h-8.172a2 2 0 00-1.414.586L3 12z" />
|
||||
|
||||
const ClearIcon = ({ className='h-6 w-6' }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2M3 12l6.414 6.414a2 2 0 001.414.586H19a2 2 0 002-2V7a2 2 0 00-2-2h-8.172a2 2 0 00-1.414.586L3 12z" />
|
||||
<ClearIconInner></ClearIconInner>
|
||||
</svg>
|
||||
)
|
||||
|
||||
|
|
15
sites/shared/components/icons/flip.js
Normal file
15
sites/shared/components/icons/flip.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
const Triangle = ({transform='translate(0,0)', fill="currentColor"}) => <path strokeLinecap="round" strokeLinejoin="round" transform={transform} style={{fill}} transform-origin="12 12" d="M1 12m9 3m-6 4h2c3 0 3 -3 3-3L9 3c-0-1.732 -2.25-2.6125 -3.325 -.77L2 16c-.77 1.333.192 3 1.732 3z" />
|
||||
|
||||
const Line = () => <path strokeLinecap="round" strokeLinejoin="round" transform="translate(12, 2)" d="M0 0L0 20" />
|
||||
|
||||
export const FlipIconInner = ({x=0, y=0, rotate=0, ...style}) => <g transform={`translate(${x},${y}) rotate(${rotate})`} transform-origin="12 12" style={style}>
|
||||
<Triangle fill="none" transform="translate(0, 2.5)"/>
|
||||
<Line/>
|
||||
<Triangle transform="scale(-1,1) translate(0,2.5)"/>
|
||||
</g>
|
||||
|
||||
export default function({ className="h-6 w-6" }) {
|
||||
return <svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<FlipIconInner></FlipIconInner>
|
||||
</svg>
|
||||
}
|
7
sites/shared/components/icons/rotate.js
Normal file
7
sites/shared/components/icons/rotate.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
export const RotateIconInner = ({flipX=false}) => <path strokeLinecap="round" strokeLinejoin="round" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" transform={flipX ? 'scale(-1,1)' : ''} transform-origin="12 12"/>
|
||||
|
||||
export default function () {
|
||||
return <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<RotateIconInner></RotateIconInner>
|
||||
</svg>
|
||||
}
|
6
sites/shared/components/icons/sheet.js
Normal file
6
sites/shared/components/icons/sheet.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
/* Sourced from heroicons.com - Thanks guys! */
|
||||
|
||||
export default function () {
|
||||
return <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16l3.5-2 3.5 2 3.5-2 3.5 2z" />
|
||||
</svg>}
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react'
|
||||
import {forwardRef} from 'react'
|
||||
import Path from '../path'
|
||||
import Point from '../point'
|
||||
import Snippet from '../snippet'
|
||||
|
@ -85,7 +85,7 @@ const XrayPart = props => {
|
|||
)
|
||||
}
|
||||
|
||||
export const PartInner = props => {
|
||||
export const PartInner = forwardRef((props, ref) => {
|
||||
const { partName, part, gist } = props
|
||||
|
||||
const grid = gist.paperless ? (
|
||||
|
@ -99,7 +99,7 @@ export const PartInner = props => {
|
|||
/>
|
||||
) : null
|
||||
|
||||
return (<>
|
||||
return (<g ref={ref}>
|
||||
{grid}
|
||||
{
|
||||
gist._state?.xray?.enabled &&
|
||||
|
@ -133,14 +133,15 @@ export const PartInner = props => {
|
|||
{...props}
|
||||
/>
|
||||
))}
|
||||
</>)
|
||||
}
|
||||
</g>)
|
||||
})
|
||||
|
||||
const Part = props => {
|
||||
const { partName, part} = props
|
||||
|
||||
return (
|
||||
<g {...getProps(part)} id={`part-${partName}`}>
|
||||
{PartInner(props)}
|
||||
<PartInner {...props}/>
|
||||
</g>
|
||||
)
|
||||
}
|
||||
|
|
66
sites/shared/components/workbench/layout/draft/buttons.js
Normal file
66
sites/shared/components/workbench/layout/draft/buttons.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
import {FlipIconInner} from 'shared/components/icons/flip'
|
||||
import {RotateIconInner} from 'shared/components/icons/rotate'
|
||||
import {ClearIconInner} from 'shared/components/icons/clear'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
const rectSize = 24
|
||||
|
||||
const Button = ({onClickCb, transform, Icon, children}) => {
|
||||
const _onClick = (event) => {
|
||||
event.stopPropagation();
|
||||
onClickCb(event);
|
||||
}
|
||||
|
||||
return <g className="svg-layout-button group" transform={transform}>
|
||||
<rect width={rectSize} height={rectSize} className="button"/>
|
||||
<Icon />
|
||||
<text className="invisible group-hover:visible text-xl">{children}</text>
|
||||
<rect width={rectSize} height={rectSize} onClick={_onClick} className="fill-transparent"/>
|
||||
</g>}
|
||||
|
||||
/** buttons for manipulating the part */
|
||||
const Buttons = ({ transform, flip, rotate, setRotate, resetPart, rotate90}) => {
|
||||
const {t} = useTranslation('workbench')
|
||||
return (
|
||||
<g transform={transform} >
|
||||
{rotate
|
||||
? <circle cx="0" cy="0" r="50" className='stroke-2xl muted' />
|
||||
: <path d="M -50, 0 l 100,0 M 0,-50 l 0,100" className="stroke-2xl muted" />
|
||||
}
|
||||
<Button
|
||||
onClickCb={resetPart}
|
||||
transform={`translate(${rectSize/-2}, ${rectSize/-2})`}
|
||||
Icon={ClearIconInner}>
|
||||
{t('toolbar.resetPart')}
|
||||
</Button>
|
||||
<Button
|
||||
onClickCb={() => rotate90(-1)}
|
||||
transform={`translate(${rectSize* -2.7}, ${rectSize/-2})`}
|
||||
Icon={RotateIconInner}
|
||||
>
|
||||
{t('toolbar.rotateCCW')}
|
||||
</Button>
|
||||
<Button
|
||||
onClickCb={() => flip('y')}
|
||||
transform={`translate(${rectSize* 0.6}, ${rectSize/-2})`}
|
||||
Icon={() => <FlipIconInner rotate="270" />}
|
||||
>
|
||||
{t('toolbar.flipY')}
|
||||
</Button>
|
||||
<Button
|
||||
onClickCb={() => flip('x')}
|
||||
transform={`translate(${rectSize* -1.6}, ${rectSize/-2})`}
|
||||
Icon={FlipIconInner}>
|
||||
{t('toolbar.flipX')}
|
||||
</Button>
|
||||
<Button
|
||||
onClickCb={() => rotate90()}
|
||||
transform={`translate(${rectSize* 1.7}, ${rectSize/-2})`}
|
||||
Icon={() => <RotateIconInner flipX={true}/>}>
|
||||
{t('toolbar.rotateCW')}
|
||||
</Button>
|
||||
</g>
|
||||
)
|
||||
}
|
||||
|
||||
export default Buttons
|
|
@ -2,27 +2,15 @@ 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 => {
|
||||
if (!props.gistReady) {return null}
|
||||
const { patternProps, gist, updateGist ,app, bgProps={} } = props
|
||||
const { layout=false } = gist
|
||||
const { patternProps, gist, updateGist, app, bgProps={}, fitLayoutPart = false, layoutType="printLayout"} = props
|
||||
|
||||
let layout = {...props.layout}
|
||||
const svgRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!layout) {
|
||||
// On the initial draft, core does the layout, so we set the layout to the auto-layout
|
||||
// After this, core won't handle layout anymore. It's up to the user from this point onwards
|
||||
updateGist(['layout'], {
|
||||
...patternProps.autoLayout,
|
||||
width: patternProps.width,
|
||||
height: patternProps.height
|
||||
}, false)
|
||||
}
|
||||
}, [layout])
|
||||
|
||||
if (!patternProps || !layout) return null
|
||||
if (!patternProps) return null
|
||||
|
||||
// Helper method to update part layout and re-calculate width * height
|
||||
const updateLayout = (name, config, history=true) => {
|
||||
|
@ -34,7 +22,9 @@ const Draft = props => {
|
|||
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
|
||||
|
@ -49,7 +39,13 @@ const Draft = props => {
|
|||
newLayout.height = bottomRight.y - topLeft.y
|
||||
newLayout.bottomRight = bottomRight
|
||||
newLayout.topLeft = topLeft
|
||||
updateGist(['layout'], newLayout, history)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,19 +56,25 @@ const Draft = props => {
|
|||
|
||||
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={{maxHeight: '100vh'}}
|
||||
style={{height: '90vh'}}
|
||||
>
|
||||
<Defs {...patternProps} />
|
||||
<style>{`:root { --pattern-scale: ${gist.scale || 1}}`}</style>
|
||||
<g>
|
||||
<rect x="0" y="0" width={patternProps.width} height={patternProps.height} {...bgProps} />
|
||||
<rect x="0" y="0" width={layout.width} height={layout.height} {...bgProps} />
|
||||
{[
|
||||
partList.filter(name => name === 'pages'),
|
||||
partList.filter(name => name !== 'pages'),
|
||||
partList.filter(name => name === props.layoutPart),
|
||||
partList.filter(name => name !== props.layoutPart),
|
||||
].map(list => list.map(name => (
|
||||
<Part {...{
|
||||
key:name,
|
||||
|
@ -82,10 +84,13 @@ const Draft = props => {
|
|||
app,
|
||||
gist,
|
||||
updateLayout,
|
||||
isLayoutPart: name === props.layoutPart
|
||||
}}/>
|
||||
)))}
|
||||
</g>
|
||||
</Svg>
|
||||
</TransformComponent>
|
||||
</TransformWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -49,33 +49,8 @@ import { getProps, angle } from '../../draft/utils'
|
|||
import { drag } from 'd3-drag'
|
||||
import { select } from 'd3-selection'
|
||||
import { useRef, useState, useEffect} from 'react'
|
||||
import Buttons from './buttons'
|
||||
|
||||
/** buttons for manipulating the part */
|
||||
const Buttons = ({ transform, flip, rotate, setRotate, resetPart }) => {
|
||||
const letter = 'F'
|
||||
const style = { style: {fill: 'white', fontSize: 18, fontWeight: 'bold', textAnchor: 'middle'} }
|
||||
|
||||
return (
|
||||
<g transform={transform}>
|
||||
{rotate
|
||||
? <circle cx="0" cy="0" r="50" className='stroke-2xl muted' />
|
||||
: <path d="M -50, 0 l 100,0 M 0,-50 l 0,100" className="stroke-2xl muted" />
|
||||
}
|
||||
<g className="svg-layout-button" onClick={resetPart}>
|
||||
<rect x="-10" y="-10" width="20" height="20" />
|
||||
<text x="0" y="10" {...style}>{letter}</text>
|
||||
</g>
|
||||
<g className="svg-layout-button" onClick={() => flip('y')}>
|
||||
<rect x="10" y="-10" width="20" height="20" className="button" />
|
||||
<text x="20" y="10" {...style} transform="scale(1,-1)">{letter}</text>
|
||||
</g>
|
||||
<g className="svg-layout-button" onClick={() => flip('x')}>
|
||||
<rect x="-30" y="-10" width="20" height="20" className="button" />
|
||||
<text x="20" y="10" {...style} transform="scale(-1,1)">{letter}</text>
|
||||
</g>
|
||||
</g>
|
||||
)
|
||||
}
|
||||
|
||||
const Part = props => {
|
||||
const { layout, part, partName} = props
|
||||
|
@ -88,20 +63,23 @@ const Part = props => {
|
|||
// Use a ref for direct DOM manipulation
|
||||
const partRef = useRef(null)
|
||||
const centerRef = useRef(null)
|
||||
const innerRef = useRef(null)
|
||||
|
||||
// State variable to switch between moving or rotating the part
|
||||
const [rotate, setRotate] = useState(false)
|
||||
|
||||
// update the layout on mount
|
||||
useEffect(() => {
|
||||
if (partRef.current) updateLayout(false)
|
||||
}, [partRef])
|
||||
if (partRef.current && !props.isLayoutPart) {
|
||||
updateLayout(false)
|
||||
}
|
||||
}, [partRef, partLayout])
|
||||
|
||||
// Initialize drag handler
|
||||
useEffect(() => {
|
||||
if (!partRef.current) {return}
|
||||
if (props.isLayoutPart) return
|
||||
handleDrag(select(partRef.current))
|
||||
}, [rotate, layout])
|
||||
}, [rotate, partRef, partLayout])
|
||||
|
||||
// These are kept as vars because re-rendering on drag would kill performance
|
||||
// Managing the difference between re-render and direct DOM updates makes this
|
||||
|
@ -121,6 +99,17 @@ const Part = props => {
|
|||
/** get the delta rotation from the start of the drag event to now */
|
||||
const getRotation = (event) => angle(center, event.subject) - angle(center, { x:event.x, y: event.y });
|
||||
|
||||
const setTransforms = () => {
|
||||
// get the transform attributes
|
||||
const transforms = generatePartTransform(translateX, translateY, rotation, flipX, flipY, part);
|
||||
|
||||
const me = select(partRef.current);
|
||||
for (var t in transforms) {
|
||||
me.attr(t, transforms[t])
|
||||
}
|
||||
}
|
||||
|
||||
let didDrag = false;
|
||||
const handleDrag = drag()
|
||||
// subject allows us to save data from the start of the event to use throughout event handing
|
||||
.subject(function(event) {
|
||||
|
@ -131,8 +120,13 @@ const Part = props => {
|
|||
{x: translateX, y: translateY}
|
||||
})
|
||||
.on('drag', function(event) {
|
||||
if (!event.dx && !event.dy) return
|
||||
|
||||
if (rotate) {
|
||||
let newRotation = getRotation(event);
|
||||
if (event.sourceEvent.shiftKey) {
|
||||
newRotation = Math.ceil(newRotation/15) * 15
|
||||
}
|
||||
// reverse the rotation direction one time per flip. if we're flipped both directions, rotation will be positive again
|
||||
if (flipX) newRotation *= -1
|
||||
if (flipY) newRotation *= -1
|
||||
|
@ -144,46 +138,47 @@ const Part = props => {
|
|||
translateY = event.y
|
||||
}
|
||||
|
||||
// get the transform attributes
|
||||
const transforms = generatePartTransform(translateX, translateY, rotation, flipX, flipY, part);
|
||||
|
||||
const me = select(this);
|
||||
for (var t in transforms) {
|
||||
me.attr(t, transforms[t])
|
||||
}
|
||||
didDrag = true;
|
||||
setTransforms()
|
||||
})
|
||||
.on('end', function(event) {
|
||||
// save to gist
|
||||
updateLayout()
|
||||
if (didDrag) updateLayout()
|
||||
|
||||
didDrag = false
|
||||
})
|
||||
|
||||
const resetPart = () => {
|
||||
const resetPart = (event) => {
|
||||
rotation = 0
|
||||
flipX = 0
|
||||
flipY = 0
|
||||
updateLayout()
|
||||
}
|
||||
const toggleDragRotate = () => {
|
||||
if (!partRef.current) {return}
|
||||
if (!partRef.current || props.isLayoutPart) {return}
|
||||
updateLayout()
|
||||
setRotate(!rotate)
|
||||
}
|
||||
|
||||
const updateLayout = (history=true) => {
|
||||
const partRect = partRef.current.getBoundingClientRect();
|
||||
const matrix = partRef.current.ownerSVGElement.getScreenCTM().inverse();
|
||||
if (!partRef.current || props.isLayoutPart) return
|
||||
|
||||
setTransforms()
|
||||
const partRect = innerRef.current.getBoundingClientRect();
|
||||
const matrix = innerRef.current.ownerSVGElement.getScreenCTM().inverse();
|
||||
|
||||
const domToSvg = (point) => DOMPointReadOnly.fromPoint(point).matrixTransform(matrix)
|
||||
|
||||
// include the new top left and bottom right to ease calculating the pattern width and height
|
||||
const tl = domToSvg({x: partRect.left, y: partRect.top});
|
||||
const br = domToSvg({x: partRect.right, y: partRect.bottom});
|
||||
const br = domToSvg({x: partRect.right, y: props.isLayoutPart ? 0 : partRect.bottom});
|
||||
|
||||
props.updateLayout(partName, {
|
||||
move: {
|
||||
x: translateX,
|
||||
y: translateY,
|
||||
},
|
||||
rotate: rotation,
|
||||
rotate: rotation % 360,
|
||||
flipX,
|
||||
flipY,
|
||||
tl,
|
||||
|
@ -198,30 +193,44 @@ const Part = props => {
|
|||
updateLayout()
|
||||
}
|
||||
|
||||
const rotate90 = (direction = 1) => {
|
||||
if (flipX) direction *= -1
|
||||
if (flipY) direction *= -1
|
||||
|
||||
rotation += 90 * direction
|
||||
|
||||
updateLayout()
|
||||
}
|
||||
|
||||
if (Object.keys(part.snippets).length === 0 && Object.keys(part.paths).length === 0) return null;
|
||||
|
||||
return (
|
||||
<g
|
||||
{...getProps(part)}
|
||||
id={`part-${partName}`}
|
||||
ref={partName === 'pages' ? null : partRef}
|
||||
onClick={toggleDragRotate}
|
||||
transform-origin={`${center.x} ${center.y}`}
|
||||
ref={partRef}
|
||||
{...getProps(part)}
|
||||
>
|
||||
{PartInner(props)}
|
||||
{partName !== 'pages' && <>
|
||||
<PartInner {...props} ref={innerRef}/>
|
||||
{!props.isLayoutPart && <>
|
||||
<text x={center.x} y={center.y} ref={centerRef} />
|
||||
<rect
|
||||
ref={partRef}
|
||||
x={part.topLeft.x}
|
||||
y={part.topLeft.y}
|
||||
width={part.width}
|
||||
height={part.height}
|
||||
className={`layout-rect ${rotate ? 'rotate' : 'move'}`}
|
||||
id={`${partName}-layout-rect`}
|
||||
onClick={toggleDragRotate}
|
||||
/>
|
||||
<Buttons
|
||||
transform={`translate(${part.topLeft.x + part.width/2}, ${part.topLeft.y + part.height/2})`}
|
||||
transform={`translate(${center.x}, ${center.y}) rotate(${-rotation}) scale(${flipX ? -1 : 1},${flipY ? -1 : 1})`}
|
||||
flip={flip}
|
||||
rotate={rotate}
|
||||
setRotate={setRotate}
|
||||
resetPart={resetPart}
|
||||
rotate90={rotate90}
|
||||
partName={partName}
|
||||
/>
|
||||
</>}
|
||||
</g>
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { useEffect } from 'react'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Settings from './settings'
|
||||
import Draft from '../draft/index'
|
||||
import pluginBuilder from './plugin'
|
||||
|
||||
const PrintLayout = props => {
|
||||
|
||||
useEffect(() => {
|
||||
if (props.gist?._state?.xray?.enabled) props.updateGist(
|
||||
['_state', 'xray', 'enabled'],
|
||||
|
@ -15,14 +14,21 @@ const PrintLayout = props => {
|
|||
|
||||
const { t } = useTranslation(['workbench'])
|
||||
|
||||
const draft = new props.design(props.gist).use(pluginBuilder(
|
||||
const draft = props.draft
|
||||
draft.use(pluginBuilder(
|
||||
props.gist?._state?.layout?.forPrinting?.page?.size,
|
||||
props.gist?._state?.layout?.forPrinting?.page?.orientation,
|
||||
))
|
||||
let patternProps
|
||||
let layout
|
||||
try {
|
||||
draft.draft()
|
||||
patternProps = draft.getRenderProps()
|
||||
layout = draft.settings.layout === true ? {
|
||||
...patternProps.autoLayout,
|
||||
width: patternProps.width,
|
||||
height: patternProps.height
|
||||
} : draft.settings.layout
|
||||
} catch(err) {
|
||||
console.log(err, props.gist)
|
||||
}
|
||||
|
@ -47,6 +53,8 @@ const PrintLayout = props => {
|
|||
patternProps={patternProps}
|
||||
bgProps={bgProps}
|
||||
gistReady={props.gistReady}
|
||||
layoutPart="pages"
|
||||
layout={layout}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -26,7 +26,7 @@ const PrintLayoutSettings = props => {
|
|||
</div>
|
||||
<button
|
||||
key="reset"
|
||||
onClick={() => props.unsetGist('layout')}
|
||||
onClick={() => props.unsetGist(['layouts', 'printLayout'])}
|
||||
className="btn btn-primary btn-outline"
|
||||
>
|
||||
<ClearIcon className="h-6 w-6 mr-2"/>
|
||||
|
|
|
@ -86,7 +86,7 @@ const WorkbenchMenu = props => {
|
|||
return (
|
||||
<nav className="grow mb-12">
|
||||
<ViewMenu {...props} />
|
||||
{props.gist?._state?.view === 'draft' && (
|
||||
{['draft', 'cuttingLayout', 'printingLayout'].indexOf(props.gist?._state?.view) > -1 && (
|
||||
<>
|
||||
<DesignOptions {...props} />
|
||||
<CoreSettings {...props} />
|
||||
|
|
|
@ -90,6 +90,7 @@ const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false
|
|||
|
||||
// Helper methods to manage the gist state
|
||||
const updateWBGist = useMemo(() => (path, value, closeNav=false, addToHistory=true) => {
|
||||
console.warn('updating gist')
|
||||
updateGist(path, value, addToHistory)
|
||||
// Force close of menu on mobile if it is open
|
||||
if (closeNav && app.primaryMenu) app.setPrimaryMenu(false)
|
||||
|
@ -112,8 +113,9 @@ const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false
|
|||
|
||||
// Generate the draft here so we can pass it down
|
||||
let draft = false
|
||||
if (['draft', 'events', 'test'].indexOf(gist._state?.view) !== -1) {
|
||||
draft = new design(gist)
|
||||
if (['draft', 'events', 'test', 'printingLayout'].indexOf(gist._state?.view) !== -1) {
|
||||
const layout = (gist._state.view === 'printingLayout' && gist.layouts?.printLayout) || gist.layout || true
|
||||
draft = new design({...gist, layout})
|
||||
if (gist.renderer === 'svg') draft.use(theme)
|
||||
try {
|
||||
if (gist._state.view !== 'test') draft.draft()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import useLocalStorage from './useLocalStorage';
|
||||
import set from 'lodash.set'
|
||||
import unset from 'lodash.unset'
|
||||
import cloneDeep from 'lodash.clonedeep'
|
||||
import cloneDeep from 'lodash.cloneDeep'
|
||||
import defaultSettings from 'shared/components/workbench/default-settings.js'
|
||||
import {useState} from 'react'
|
||||
|
||||
|
@ -29,7 +29,8 @@ export function useGist(design, app) {
|
|||
let oldGist
|
||||
_setGist((gistState) => {
|
||||
// have to clone it or nested objects will be referenced instead of copied, which defeats the purpose
|
||||
oldGist = cloneDeep(gistState);
|
||||
if (addToHistory) oldGist = cloneDeep(gistState)
|
||||
|
||||
return typeof newGist === 'function' ? newGist(cloneDeep(gistState)) : newGist
|
||||
})
|
||||
|
||||
|
|
|
@ -267,14 +267,6 @@ summary::-webkit-details-marker {
|
|||
display: none;
|
||||
}
|
||||
|
||||
/* Style for slider track */
|
||||
input[type=range]::-webkit-slider-runnable-track {
|
||||
background: #ffffff44;
|
||||
}
|
||||
|
||||
input[type=range]:focus::-webkit-slider-runnable-track {
|
||||
background: #ffffff66;
|
||||
}
|
||||
|
||||
input[type=range]::-moz-range-track {
|
||||
background: #3071a9;
|
||||
|
|
|
@ -61,6 +61,7 @@ svg.freesewing.pattern {
|
|||
.bold { font-weight: bold; }
|
||||
|
||||
.center { text-anchor: middle; }
|
||||
.baseline-center {dominant-baseline: central;}
|
||||
.right { text-anchor: end; }
|
||||
|
||||
/* muted page numbers */
|
||||
|
@ -84,10 +85,13 @@ svg.freesewing.pattern {
|
|||
}
|
||||
.svg-layout-button > rect.button {
|
||||
fill: var(--pattern-note);
|
||||
fill-opacity: 0.3;
|
||||
fill-opacity: 0.5;
|
||||
stroke: none;
|
||||
}
|
||||
.svg-layout-button:hover > rect {
|
||||
.svg-layout-button path {
|
||||
stroke-width: calc(var(--pattern-stroke) * 2 * var(--pattern-scale));;
|
||||
}
|
||||
.svg-layout-button:hover > rect.button {
|
||||
fill: var(--pattern-lining);
|
||||
stroke: none;
|
||||
fill-opacity: 1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue