diff --git a/config/dependencies.yaml b/config/dependencies.yaml
index c437a916497..fba98bbc1d1 100644
--- a/config/dependencies.yaml
+++ b/config/dependencies.yaml
@@ -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'
diff --git a/designs/bella/src/back.mjs b/designs/bella/src/back.mjs
index adb64cd9590..9d4565bf127 100644
--- a/designs/bella/src/back.mjs
+++ b/designs/bella/src/back.mjs
@@ -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) {
diff --git a/designs/carlton/src/back.mjs b/designs/carlton/src/back.mjs
index 75ae0808ca0..81181bab8dd 100644
--- a/designs/carlton/src/back.mjs
+++ b/designs/carlton/src/back.mjs
@@ -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',
diff --git a/plugins/plugin-bundle/src/index.mjs b/plugins/plugin-bundle/src/index.mjs
index d72b9f954fe..d7466568b35 100644
--- a/plugins/plugin-bundle/src/index.mjs
+++ b/plugins/plugin-bundle/src/index.mjs
@@ -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,38 +30,44 @@ const bundledPlugins = [
scaleboxPlugin,
sprinklePlugin,
titlePlugin,
+ pluginCutlist,
]
-function bundleHooks() {
- const hooks = {}
- for (const plugin of bundledPlugins) {
- for (const i in plugin.hooks) {
- if (typeof hooks[i] === 'undefined') hooks[i] = []
- const hook = plugin.hooks[i]
- if (typeof hook === 'function') hooks[i].push(hook)
- else if (typeof hook === 'object') {
- for (let method of hook) hooks[i].push(method)
- }
+const hooks = {}
+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]
+ if (typeof hook === 'function') hooks[i].push(hook)
+ else if (typeof hook === 'object') {
+ for (let method of hook) hooks[i].push(method)
}
}
-
- return hooks
}
-function bundleMacros() {
- const macros = {}
- for (const plugin of bundledPlugins) {
- for (const i in plugin.macros) macros[i] = plugin.macros[i]
- }
+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
diff --git a/sites/shared/components/workbench/layout/cut/index.mjs b/sites/shared/components/workbench/layout/cut/index.mjs
index eb5355d68ae..6727cf9db05 100644
--- a/sites/shared/components/workbench/layout/cut/index.mjs
+++ b/sites/shared/components/workbench/layout/cut/index.mjs
@@ -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,46 +17,89 @@ 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 || {}
- // 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),
- }
- draft.use(fabricPlugin(layoutSettings))
- draft.use(pluginCutlist)
- draft.use(cutLayoutPlugin)
+ 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,
+ sheetHeight,
+ }
+ draft.use(fabricPlugin(layoutSettings))
+ draft.use(pluginCutlist)
+ draft.use(cutLayoutPlugin(cutFabric))
+ // draft the pattern
+ draft.draft()
+ 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])
- let patternProps
- try {
- // draft the pattern
- draft.draft()
- patternProps = draft.getRenderProps()
- } catch (err) {
- console.log(err, props.gist)
- }
const bgProps = { fill: 'url(#page)' }
let name = props.design.designConfig.data.name
name = name.replace('@freesewing/', '')
- return (
+
+ return patternProps ? (
{t('layoutThing', { thing: name }) + ': ' + t('forCutting')}
-
-
+
+
+ {cutFabrics.map((title) => (
+
+ ))}
+
+
+
- )
+ ) : null
}
diff --git a/sites/shared/components/workbench/layout/cut/plugin-cut-layout.mjs b/sites/shared/components/workbench/layout/cut/plugin-cut-layout.mjs
index 46354c69600..34faf9c693b 100644
--- a/sites/shared/components/workbench/layout/cut/plugin-cut-layout.mjs
+++ b/sites/shared/components/workbench/layout/cut/plugin-cut-layout.mjs
@@ -1,70 +1,80 @@
const prefix = 'mirroredOnFold'
const redraft = ({ part }) => part
-export const cutLayoutPlugin = {
- hooks: {
- postPartDraft: (pattern) => {
- const partCutlist = pattern.setStores[pattern.activeSet].get(['cutlist', pattern.activePart])
- if (!partCutlist) return
+export const cutLayoutPlugin = function (material) {
+ return {
+ hooks: {
+ postPartDraft: (pattern) => {
+ if (pattern.activePart.startsWith('cut.') || pattern.activePart === 'fabric') return
- const { macro } = pattern.parts[pattern.activeSet][pattern.activePart].shorthand()
- if (partCutlist.cutOnFold) macro('mirrorOnFold', { fold: partCutlist.cutOnFold })
+ const partCutlist = pattern.setStores[pattern.activeSet].get([
+ 'cutlist',
+ pattern.activePart,
+ ])
- if (partCutlist.materials) {
- for (const material in partCutlist.materials) {
- for (var i = 1; i < partCutlist.materials[material]; i++) {
- pattern.addPart({
- name: `${pattern.activePart}_${material}_${i}`,
- from: pattern.activePart,
- draft: redraft,
- })
- }
+ 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()
+ macro('mirrorOnFold', { fold: partCutlist.cutOnFold })
+ }
+
+ for (var i = 1; i < partCutlist?.materials?.[material].cut; i++) {
+ const dupPartName = `cut.${pattern.activePart}.${material}_${i + 1}`
+ pattern.addPart({
+ name: dupPartName,
+ from: pattern.config.parts[pattern.activePart],
+ draft: redraft,
+ })
+ }
+ },
},
- },
- macros: {
- mirrorOnFold: ({ fold }, { paths, snippets, utils, macro, points }) => {
- const mirrorPaths = []
- for (const p in paths) {
- if (!paths[p].hidden && !p.startsWith(prefix)) mirrorPaths.push(paths[p])
- }
+ macros: {
+ mirrorOnFold: ({ fold }, { paths, snippets, utils, macro, points }) => {
+ const mirrorPaths = []
+ for (const p in paths) {
+ if (!paths[p].hidden && !p.startsWith(prefix)) mirrorPaths.push(paths[p])
+ }
- const mirrorPoints = []
- const snippetsByType = {}
- for (var s in snippets) {
- const snip = snippets[s]
- if (['logo'].indexOf(snip.def) > -1) continue
+ const mirrorPoints = []
+ const snippetsByType = {}
+ for (var s in snippets) {
+ const snip = snippets[s]
+ if (['logo'].indexOf(snip.def) > -1) continue
- snippetsByType[snip.def] = snippetsByType[snip.def] || []
+ snippetsByType[snip.def] = snippetsByType[snip.def] || []
- mirrorPoints.push(snip.anchor)
- for (var pName in points) {
- if (points[pName] === snip.anchor) {
- snippetsByType[snip.def].push(prefix + utils.capitalize(pName))
- break
+ mirrorPoints.push(snip.anchor)
+ for (var pName in points) {
+ if (points[pName] === snip.anchor) {
+ snippetsByType[snip.def].push(prefix + utils.capitalize(pName))
+ break
+ }
}
}
- }
- let unnamed = 0
- macro('mirror', {
- paths: Object.values(mirrorPaths),
- points: mirrorPoints,
- mirror: fold,
- prefix,
- nameFormat: (path) => {
- unnamed++
- return `${prefix}_${unnamed}`
- },
- })
-
- for (var def in snippetsByType) {
- macro('sprinkle', {
- snippet: def,
- on: snippetsByType[def],
+ let unnamed = 0
+ macro('mirror', {
+ paths: Object.values(mirrorPaths),
+ points: mirrorPoints,
+ mirror: fold,
+ prefix,
+ nameFormat: (path) => {
+ unnamed++
+ return `${prefix}_${unnamed}`
+ },
})
- }
+
+ for (var def in snippetsByType) {
+ macro('sprinkle', {
+ snippet: def,
+ on: snippetsByType[def],
+ })
+ }
+ },
},
- },
+ }
}
diff --git a/sites/shared/components/workbench/layout/cut/settings.mjs b/sites/shared/components/workbench/layout/cut/settings.mjs
index 0fe4c2153ed..7156e591e9b 100644
--- a/sites/shared/components/workbench/layout/cut/settings.mjs
+++ b/sites/shared/components/workbench/layout/cut/settings.mjs
@@ -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) => {
- evt.stopPropagation()
- let evtVal = evt.target.value
- // set Val immediately so that the input reflects it
- setVal(evtVal)
+ const update = (evt) => {
+ evt.stopPropagation()
+ let evtVal = evt.target.value
+ // set Val immediately so that the input reflects it
+ 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)
- }
- },
- [gist.units]
- )
+ let useVal = measurementAsMm(evtVal, gist.units)
+ // only set to the gist if it's valid
+ if (!isNaN(useVal)) {
+ updateGist(['_state', 'layout', 'forCutting', 'fabric', cutFabric, 'sheetWidth'], useVal)
+ }
+ }
return (
-
+