cutting layout page has tabs for each fabric type. parts duplication
This commit is contained in:
parent
cd034a7cf3
commit
29e3ba6323
12 changed files with 224 additions and 158 deletions
|
@ -380,6 +380,7 @@ shared:
|
|||
'lodash.clonedeep': '4.5.0'
|
||||
'lodash.orderby': *_orderby
|
||||
'lodash.unset': *_unset
|
||||
'lodash.get': *_get
|
||||
'mdast-util-toc': '6.1.0'
|
||||
'pdfkit': '0.13.0'
|
||||
'postcss-for': '2.1.1'
|
||||
|
|
|
@ -65,6 +65,7 @@ export const back = {
|
|||
measurements,
|
||||
log,
|
||||
part,
|
||||
addCut,
|
||||
}) => {
|
||||
// Get to work
|
||||
points.cbNeck = new Point(0, measurements.neck * options.backNeckCutout)
|
||||
|
@ -269,6 +270,8 @@ export const back = {
|
|||
on: ['armholePitch', 'bustCenter'],
|
||||
})
|
||||
|
||||
addCut()
|
||||
|
||||
if (sa) paths.sa = paths.saBase.offset(sa).attr('class', 'fabric sa')
|
||||
|
||||
if (paperless) {
|
||||
|
|
|
@ -16,6 +16,7 @@ function draftCarltonBack({
|
|||
paths,
|
||||
Path,
|
||||
part,
|
||||
addCut,
|
||||
}) {
|
||||
calculateRatios(part)
|
||||
// Belt width
|
||||
|
@ -95,6 +96,8 @@ function draftCarltonBack({
|
|||
.line(points.bpStart)
|
||||
.attr('class', 'dashed')
|
||||
|
||||
addCut(2)
|
||||
addCut(2, 'lining')
|
||||
if (complete) {
|
||||
macro('sprinkle', {
|
||||
snippet: 'bnotch',
|
||||
|
|
|
@ -12,6 +12,7 @@ import { roundPlugin } from '../../plugin-round/src/index.mjs'
|
|||
import { scaleboxPlugin } from '../../plugin-scalebox/src/index.mjs'
|
||||
import { sprinklePlugin } from '../../plugin-sprinkle/src/index.mjs'
|
||||
import { titlePlugin } from '../../plugin-title/src/index.mjs'
|
||||
import { pluginCutlist } from '../../plugin-cutlist/src/index.mjs'
|
||||
import { name, version } from '../data.mjs'
|
||||
|
||||
const bundledPlugins = [
|
||||
|
@ -29,11 +30,14 @@ const bundledPlugins = [
|
|||
scaleboxPlugin,
|
||||
sprinklePlugin,
|
||||
titlePlugin,
|
||||
pluginCutlist,
|
||||
]
|
||||
|
||||
function bundleHooks() {
|
||||
const hooks = {}
|
||||
for (const plugin of bundledPlugins) {
|
||||
const macros = {}
|
||||
const store = []
|
||||
|
||||
function bundleHooks(plugin) {
|
||||
for (const i in plugin.hooks) {
|
||||
if (typeof hooks[i] === 'undefined') hooks[i] = []
|
||||
const hook = plugin.hooks[i]
|
||||
|
@ -44,23 +48,26 @@ function bundleHooks() {
|
|||
}
|
||||
}
|
||||
|
||||
return hooks
|
||||
}
|
||||
|
||||
function bundleMacros() {
|
||||
const macros = {}
|
||||
for (const plugin of bundledPlugins) {
|
||||
function bundleMacros(plugin) {
|
||||
for (const i in plugin.macros) macros[i] = plugin.macros[i]
|
||||
}
|
||||
|
||||
return macros
|
||||
function bundleStore(plugin) {
|
||||
if (plugin.store) store.push(...plugin.store)
|
||||
}
|
||||
|
||||
for (const plugin of bundledPlugins) {
|
||||
bundleHooks(plugin, hooks)
|
||||
bundleMacros(plugin, macros)
|
||||
bundleStore(plugin, store)
|
||||
}
|
||||
|
||||
export const plugin = {
|
||||
name,
|
||||
version,
|
||||
hooks: bundleHooks(),
|
||||
macros: bundleMacros(),
|
||||
hooks,
|
||||
macros,
|
||||
store,
|
||||
}
|
||||
|
||||
// More specifically named exports
|
||||
|
|
|
@ -4,8 +4,10 @@ import { Draft } from '../draft/index.mjs'
|
|||
import { fabricPlugin } from '../plugin-layout-part.mjs'
|
||||
import { cutLayoutPlugin } from './plugin-cut-layout.mjs'
|
||||
import { pluginCutlist } from '@freesewing/plugin-cutlist'
|
||||
import { useEffect } from 'react'
|
||||
import { measurementAsMm } from 'shared/utils.mjs'
|
||||
import { useState, useEffect, useCallback, useRef } from 'react'
|
||||
import { Tabs } from 'shared/components/mdx/tabs.mjs'
|
||||
import get from 'lodash.get'
|
||||
|
||||
export const CutLayout = (props) => {
|
||||
const { t } = useTranslation(['workbench'])
|
||||
|
@ -15,36 +17,78 @@ export const CutLayout = (props) => {
|
|||
if (props.gist?._state?.xray?.enabled) props.updateGist(['_state', 'xray', 'enabled'], false)
|
||||
})
|
||||
|
||||
const draft = props.draft
|
||||
const isImperial = props.gist.units === 'imperial'
|
||||
const gistSettings = props.gist?._state?.layout?.forCutting?.fabric || {}
|
||||
|
||||
const [patternProps, setPatternProps] = useState(undefined)
|
||||
const [cutFabrics, setCutFabrics] = useState(['fabric'])
|
||||
const [draft, setDraft] = useState()
|
||||
const [cutFabric, setCutFabric] = useState('fabric')
|
||||
|
||||
const gistSettings = get(props.gist, ['_state', 'layout', 'forCutting', 'fabric', cutFabric])
|
||||
const sheetWidth =
|
||||
gistSettings?.sheetWidth || measurementAsMm(isImperial ? 54 : 120, props.gist.units)
|
||||
const gist = props.gist
|
||||
const sheetHeight = measurementAsMm(isImperial ? 36 : 100, props.gist.units)
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
// get the appropriate layout for the view
|
||||
const layout = gist.layouts?.[gist._state.view]?.[cutFabric] || gist.layout || true
|
||||
// hand it separately to the design
|
||||
const draft = new props.design({ ...gist, layout })
|
||||
|
||||
// add the pages plugin to the draft
|
||||
const layoutSettings = {
|
||||
sheetWidth: gistSettings.sheetWidth || measurementAsMm(isImperial ? 54 : 120, props.gist.units),
|
||||
sheetHeight:
|
||||
gistSettings.sheetHeight || measurementAsMm(isImperial ? 36 : 100, props.gist.units),
|
||||
sheetWidth,
|
||||
sheetHeight,
|
||||
}
|
||||
draft.use(fabricPlugin(layoutSettings))
|
||||
draft.use(pluginCutlist)
|
||||
draft.use(cutLayoutPlugin)
|
||||
|
||||
let patternProps
|
||||
try {
|
||||
draft.use(cutLayoutPlugin(cutFabric))
|
||||
// draft the pattern
|
||||
draft.draft()
|
||||
patternProps = draft.getRenderProps()
|
||||
setPatternProps(draft.getRenderProps())
|
||||
|
||||
const cutList = draft.setStores[0].get('cutlist')
|
||||
const cf = ['fabric']
|
||||
for (const partName in cutList) {
|
||||
for (const matName in cutList[partName].materials) {
|
||||
if (!cf.includes(matName)) cf.push(matName)
|
||||
}
|
||||
}
|
||||
setCutFabrics(cf)
|
||||
} catch (err) {
|
||||
console.log(err, props.gist)
|
||||
}
|
||||
}, [cutFabric, isImperial, gist])
|
||||
|
||||
const bgProps = { fill: 'url(#page)' }
|
||||
|
||||
let name = props.design.designConfig.data.name
|
||||
name = name.replace('@freesewing/', '')
|
||||
return (
|
||||
|
||||
return patternProps ? (
|
||||
<div>
|
||||
<h2 className="capitalize">{t('layoutThing', { thing: name }) + ': ' + t('forCutting')}</h2>
|
||||
<CutLayoutSettings {...props} patternProps={patternProps} />
|
||||
<CutLayoutSettings
|
||||
{...{ ...props, patternProps, cutFabric, sheetWidth }}
|
||||
patternProps={patternProps}
|
||||
cutFabric={cutFabric}
|
||||
/>
|
||||
<div className="my-4">
|
||||
<div className="tabs">
|
||||
{cutFabrics.map((title) => (
|
||||
<button
|
||||
key={title}
|
||||
className={`text-xl font-bold capitalize tab tab-bordered grow ${
|
||||
cutFabric === title ? 'tab-active' : ''
|
||||
}`}
|
||||
onClick={() => setCutFabric(title)}
|
||||
>
|
||||
{title}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<Draft
|
||||
draft={draft}
|
||||
gist={props.gist}
|
||||
|
@ -53,8 +97,9 @@ export const CutLayout = (props) => {
|
|||
bgProps={bgProps}
|
||||
gistReady={props.gistReady}
|
||||
layoutPart="fabric"
|
||||
layoutType="cuttingLayout"
|
||||
layoutType={['cuttingLayout', cutFabric]}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
|
|
|
@ -1,26 +1,35 @@
|
|||
const prefix = 'mirroredOnFold'
|
||||
|
||||
const redraft = ({ part }) => part
|
||||
export const cutLayoutPlugin = {
|
||||
export const cutLayoutPlugin = function (material) {
|
||||
return {
|
||||
hooks: {
|
||||
postPartDraft: (pattern) => {
|
||||
const partCutlist = pattern.setStores[pattern.activeSet].get(['cutlist', pattern.activePart])
|
||||
if (!partCutlist) return
|
||||
if (pattern.activePart.startsWith('cut.') || pattern.activePart === 'fabric') return
|
||||
|
||||
const partCutlist = pattern.setStores[pattern.activeSet].get([
|
||||
'cutlist',
|
||||
pattern.activePart,
|
||||
])
|
||||
|
||||
if (!partCutlist?.materials?.[material] && material !== 'fabric') {
|
||||
pattern.parts[pattern.activeSet][pattern.activePart].hide()
|
||||
return
|
||||
}
|
||||
|
||||
if (partCutlist?.cutOnFold) {
|
||||
const { macro } = pattern.parts[pattern.activeSet][pattern.activePart].shorthand()
|
||||
if (partCutlist.cutOnFold) macro('mirrorOnFold', { fold: partCutlist.cutOnFold })
|
||||
macro('mirrorOnFold', { fold: partCutlist.cutOnFold })
|
||||
}
|
||||
|
||||
if (partCutlist.materials) {
|
||||
for (const material in partCutlist.materials) {
|
||||
for (var i = 1; i < partCutlist.materials[material]; i++) {
|
||||
for (var i = 1; i < partCutlist?.materials?.[material].cut; i++) {
|
||||
const dupPartName = `cut.${pattern.activePart}.${material}_${i + 1}`
|
||||
pattern.addPart({
|
||||
name: `${pattern.activePart}_${material}_${i}`,
|
||||
from: pattern.activePart,
|
||||
name: dupPartName,
|
||||
from: pattern.config.parts[pattern.activePart],
|
||||
draft: redraft,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
macros: {
|
||||
|
@ -68,3 +77,4 @@ export const cutLayoutPlugin = {
|
|||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +1,32 @@
|
|||
import { useMemo, useEffect, useState, useCallback } from 'react'
|
||||
import { ClearIcon } from 'shared/components/icons.mjs'
|
||||
import { useMemo, useEffect, useState, useCallback, useRef } from 'react'
|
||||
import { ClearIcon, PageIcon } from 'shared/components/icons.mjs'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { formatFraction128, measurementAsMm, round, formatMm } from 'shared/utils.mjs'
|
||||
import get from 'lodash.get'
|
||||
|
||||
const FabricSizer = ({ gist, updateGist }) => {
|
||||
const FabricSizer = ({ gist, updateGist, cutFabric, sheetWidth }) => {
|
||||
const { t } = useTranslation(['workbench'])
|
||||
const [val, setVal] = useState(500)
|
||||
|
||||
useEffect(() => {
|
||||
setVal(formatMm(gist._state?.layout?.forCutting?.fabric.sheetWidth || 500, gist.units, 'none'))
|
||||
}, [gist])
|
||||
const setFabricWidth = (width) => {}
|
||||
|
||||
let val = formatMm(sheetWidth, gist.units, 'none')
|
||||
// onChange
|
||||
const update = useCallback(
|
||||
(evt) => {
|
||||
const update = (evt) => {
|
||||
evt.stopPropagation()
|
||||
let evtVal = evt.target.value
|
||||
// set Val immediately so that the input reflects it
|
||||
setVal(evtVal)
|
||||
val = evtVal
|
||||
|
||||
let useVal = measurementAsMm(evtVal, gist.units)
|
||||
// only set to the gist if it's valid
|
||||
if (!isNaN(useVal)) {
|
||||
updateGist(['_state', 'layout', 'forCutting', 'fabric', 'sheetWidth'], useVal)
|
||||
updateGist(['_state', 'layout', 'forCutting', 'fabric', cutFabric, 'sheetWidth'], useVal)
|
||||
}
|
||||
}
|
||||
},
|
||||
[gist.units]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="flex gap-4">
|
||||
<div className="flex gap-4 px-0 font-bold items-center">
|
||||
<div className="form-control mb-2 flex flex-row" key="wrap-fabricWidth">
|
||||
<label className="input-group input-group-xs">
|
||||
<span className="label-text font-bold">{t('fabricWidth')}</span>
|
||||
<span className="label-text font-bold">{`${t(cutFabric)} ${t('width')}`}</span>
|
||||
<input
|
||||
key="input-fabricWidth"
|
||||
type="text"
|
||||
|
@ -68,30 +61,33 @@ const useFabricLength = (isImperial, height) => {
|
|||
return `${count}${isImperial ? 'yds' : 'm'}`
|
||||
}
|
||||
|
||||
export const CutLayoutSettings = ({ gist, patternProps, unsetGist, updateGist }) => {
|
||||
export const CutLayoutSettings = ({
|
||||
gist,
|
||||
patternProps,
|
||||
unsetGist,
|
||||
updateGist,
|
||||
cutFabric,
|
||||
sheetWidth,
|
||||
}) => {
|
||||
const { t } = useTranslation(['workbench'])
|
||||
|
||||
const fabricLength = useFabricLength(gist.units === 'imperial', patternProps.height)
|
||||
|
||||
return (
|
||||
<div className="flex flex-row justify-between mb-2 items-baseline">
|
||||
<FabricSizer {...{ gist, updateGist, cutFabric, sheetWidth }} />
|
||||
<div>
|
||||
<div
|
||||
className="flex flex-row justify-between
|
||||
mb-2"
|
||||
>
|
||||
<PageIcon className="h-6 w-6 mr-2 inline align-middle" />
|
||||
<span className="text-xl font-bold align-middle">{fabricLength}</span>
|
||||
</div>
|
||||
<button
|
||||
key="reset"
|
||||
onClick={() => unsetGist(['layouts', 'cuttingLayout'])}
|
||||
onClick={() => unsetGist(['layouts', 'cuttingLayout', cutFabric])}
|
||||
className="btn btn-primary btn-outline"
|
||||
>
|
||||
<ClearIcon className="h-6 w-6 mr-2" />
|
||||
{t('reset')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-row font-bold items-center px-0">
|
||||
<FabricSizer {...{ gist, updateGist }} />
|
||||
<span className="ml-2">{fabricLength}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ import { useRef } from 'react'
|
|||
import { Stack } from './stack.mjs'
|
||||
import { SvgWrapper } from '../../draft/svg.mjs'
|
||||
import { PartInner } from '../../draft/part.mjs'
|
||||
import get from 'lodash.get'
|
||||
|
||||
export const Draft = (props) => {
|
||||
const {
|
||||
draft,
|
||||
patternProps,
|
||||
gist,
|
||||
updateGist,
|
||||
|
@ -18,7 +18,8 @@ export const Draft = (props) => {
|
|||
const svgRef = useRef(null)
|
||||
if (!patternProps) return null
|
||||
// keep a fresh copy of the layout because we might manipulate it without saving to the gist
|
||||
let layout = draft.settings[0].layouts?.[layoutType] || {
|
||||
const layoutPath = ['layouts'].concat(layoutType)
|
||||
let layout = get(patternProps.settings[0], layoutPath) || {
|
||||
...patternProps.autoLayout,
|
||||
width: patternProps.width,
|
||||
height: patternProps.height,
|
||||
|
@ -53,7 +54,7 @@ export const Draft = (props) => {
|
|||
newLayout.topLeft = topLeft
|
||||
|
||||
if (history) {
|
||||
updateGist(['layouts', layoutType], newLayout, history)
|
||||
updateGist(layoutPath, newLayout, history)
|
||||
} else {
|
||||
// we don't put it in the gist if it shouldn't contribute to history because we need some of 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. This is what allows the layout to respond appropriately to settings changes. Once the user has starting playing with the layout, all bets are off
|
||||
layout = newLayout
|
||||
|
|
|
@ -117,6 +117,9 @@ const basePlugin = ({
|
|||
version,
|
||||
hooks: {
|
||||
preLayout: function (pattern) {
|
||||
if (!responsiveColumns) {
|
||||
pattern.settings[0].maxWidth = sheetWidth
|
||||
}
|
||||
// Add part
|
||||
pattern.addPart({
|
||||
name: partName,
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useTranslation } from 'next-i18next'
|
|||
|
||||
export const CoreSettingOnly = (props) => {
|
||||
const { t } = useTranslation(['app', 'parts', 'settings'])
|
||||
const list = props.draft.config.draftOrder
|
||||
const list = props.design.patternConfig.draftOrder
|
||||
const partNames = list.map((part) => ({ id: part, name: t(`parts:${part}`) }))
|
||||
|
||||
const togglePart = (part) => {
|
||||
|
|
|
@ -21,7 +21,7 @@ export const OptionComponent = (props) => {
|
|||
const Value = values[capitalize(type)]
|
||||
|
||||
try {
|
||||
const hide = opt.hide && opt.hide(props.draft.settings)
|
||||
const hide = opt.hide && opt.hide(props.gist)
|
||||
|
||||
if (hide) return null
|
||||
} catch (e) {
|
||||
|
|
|
@ -119,9 +119,7 @@ export const WorkbenchWrapper = ({
|
|||
|
||||
// Generate the draft here so we can pass it down to both the view and the options menu
|
||||
let draft = false
|
||||
if (
|
||||
['draft', 'logs', 'test', 'printingLayout', 'cuttingLayout'].indexOf(gist._state?.view) !== -1
|
||||
) {
|
||||
if (['draft', 'logs', 'test', 'printingLayout'].indexOf(gist._state?.view) !== -1) {
|
||||
gist.embed = true
|
||||
// get the appropriate layout for the view
|
||||
const layout = gist.layouts?.[gist._state.view] || gist.layout || true
|
||||
|
@ -148,7 +146,6 @@ export const WorkbenchWrapper = ({
|
|||
updateGist: updateWBGist,
|
||||
unsetGist,
|
||||
setGist,
|
||||
draft,
|
||||
feedback,
|
||||
gistReady,
|
||||
showInfo: setPopup,
|
||||
|
@ -178,7 +175,7 @@ export const WorkbenchWrapper = ({
|
|||
<LayoutComponent {...layoutProps}>
|
||||
{messages}
|
||||
<ErrorBoundary {...errorProps}>
|
||||
<Component {...componentProps} />
|
||||
<Component {...componentProps} draft={draft} />
|
||||
{popup && <Modal cancel={() => setPopup(false)}>{popup}</Modal>}
|
||||
</ErrorBoundary>
|
||||
</LayoutComponent>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue