Merge branch 'develop' into cdocs
This commit is contained in:
commit
b914b6299f
89 changed files with 1571 additions and 737 deletions
|
@ -1,7 +1,7 @@
|
||||||
# Contributing to FreeSewing
|
# Contributing to FreeSewing
|
||||||
|
|
||||||
First off,
|
First off,
|
||||||
thank you for being part of the freesewing community,
|
thank you for being part of the FreeSewing community,
|
||||||
and for taking the time to contribute! ❤️
|
and for taking the time to contribute! ❤️
|
||||||
|
|
||||||
The following is a set of guidelines for contributing to FreeSewing.
|
The following is a set of guidelines for contributing to FreeSewing.
|
||||||
|
@ -11,23 +11,24 @@ Use your best judgment, and feel free to propose changes to this document in a p
|
||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
|
|
||||||
When you engage with us, or when you engage with others,
|
When you engage with us, or when you engage with others,
|
||||||
please remember [the FreeSewing community standards](https://freesewing.org/docs/about/community-standards/).
|
please remember [the FreeSewing community standards](https://freesewing.eu/docs/about/community-standards/).
|
||||||
|
|
||||||
As a contributor, you are also expected to uphold [the FreeSewing Code of Conduct](https://freesewing.dev/guides/code-of-conduct).
|
As a contributor, you are also expected to uphold [the FreeSewing Code of Conduct](https://freesewing.dev/guides/code-of-conduct).
|
||||||
|
|
||||||
<Tip>
|
:::tip
|
||||||
|
|
||||||
##### See something, say something
|
##### See something, say something
|
||||||
|
|
||||||
Please report unacceptable behavior to [us@freesewing.org](mailto:us@freesewing.org).
|
Please report unacceptable behavior to [us@freesewing.eu](mailto:us@freesewing.eu).
|
||||||
|
|
||||||
</Tip>
|
:::
|
||||||
|
|
||||||
## I don't want to read this whole thing I just have a question!
|
## I don't want to read this whole thing I just have a question!
|
||||||
|
|
||||||
Please don't file an issue to ask a question.
|
Please don't file an issue to ask a question.
|
||||||
You'll get faster results by contacting us on Discord.
|
You'll get faster results by contacting us on Discord or the Forum.
|
||||||
You can get to our Discord server via https://discord.freesewing.org/.
|
You can get to our Discord server via https://discord.freesewing.eu/ .
|
||||||
|
You can get to our Forum via https://forum.freesewing.eu/ .
|
||||||
|
|
||||||
Please keep in mind that our community members live all over the world.
|
Please keep in mind that our community members live all over the world.
|
||||||
So what's daytime for you might be the middle of the night for others.
|
So what's daytime for you might be the middle of the night for others.
|
||||||
|
@ -35,16 +36,16 @@ Please be patient. Sooner or later, somebody will answer.
|
||||||
|
|
||||||
## What should I know before I get started?
|
## What should I know before I get started?
|
||||||
|
|
||||||
Most of FreeSewing's source code lives in [our monorepo](https://github.com/freesewing/freesewing).
|
Most of FreeSewing's source code lives in [our monorepo](https://codeberg.org/freesewing/freesewing).
|
||||||
|
|
||||||
There are some exceptions:
|
There are some exceptions:
|
||||||
|
|
||||||
- [`svgtopdf`](https://github.com/freesewing/svgtopdf): The repository holding the source code for our on-demand tiler backend
|
|
||||||
- [`tile`](https://github.com/freesewing/tile): The repository holding the source code for our command-line tiler
|
- [`tile`](https://github.com/freesewing/tile): The repository holding the source code for our command-line tiler
|
||||||
|
|
||||||
### FreeSewing packages
|
### FreeSewing packages
|
||||||
|
|
||||||
We publish a lot of JavaScript packages on NPM. You can find the full list [in the `packages` folder of our monorepo](https://github.com/freesewing/freesewing/tree/develop/packages).
|
We publish a lot of JavaScript packages on NPM. You can find the full list
|
||||||
|
[in the `packages` folder of our monorepo](https://codeberg.org/freesewing/freesewing/src/branch/develop/packages).
|
||||||
|
|
||||||
## How Can I Contribute?
|
## How Can I Contribute?
|
||||||
|
|
||||||
|
@ -55,7 +56,4 @@ This file is mostly geared towards code contributors, but there's plenty of othe
|
||||||
Unsure where to begin contributing to FreeSewing?
|
Unsure where to begin contributing to FreeSewing?
|
||||||
You can start by looking through the issues labeled [good first issue](https://codeberg.org/freesewing/freesewing/issues?q=&type=all&sort=&state=open&labels=344963).
|
You can start by looking through the issues labeled [good first issue](https://codeberg.org/freesewing/freesewing/issues?q=&type=all&sort=&state=open&labels=344963).
|
||||||
|
|
||||||
Don't be afraid to take on an issue. If you get stuck, [we'll help you out](https://discord.freesewing.org/).
|
Don't be afraid to take on an issue. If you get stuck, [we'll help you out](https://discord.freesewing.eu/).
|
||||||
|
|
||||||
|
|
||||||
<ReadMore />
|
|
||||||
|
|
|
@ -23,7 +23,9 @@
|
||||||
"cutNeckBinding.t": "The neck binding is not shown",
|
"cutNeckBinding.t": "The neck binding is not shown",
|
||||||
"cutNeckBinding.d": "The **Neck Binding** (10) is a rectangular piece of main fabric {{{ w }}} wide and {{{ l }}} long, with the grainline parallel to the length.",
|
"cutNeckBinding.d": "The **Neck Binding** (10) is a rectangular piece of main fabric {{{ w }}} wide and {{{ l }}} long, with the grainline parallel to the length.",
|
||||||
"cutWaistband.t": "The waistband is not shown",
|
"cutWaistband.t": "The waistband is not shown",
|
||||||
"cutWaistband.d": "The **Waistband** (8) is a rectangular piece of ribbing fabric {{{ w }}} wide and {{{ l }}} long, with the grainline parallel to the width."
|
"cutWaistband.d": "The **Waistband** (8) is a rectangular piece of ribbing fabric {{{ w }}} wide and {{{ l }}} long, with the grainline parallel to the width.",
|
||||||
|
"neckCircumference.t": "The neck opening is too small",
|
||||||
|
"neckCircumference.d": "The neck opening of {{{ opening }}} is smaller than the head circumference of {{{ head }}}.\n\nPlease check and adjust Collar Ease option setting as needed to ensure the neck opening is large enough to accommodate head circumference."
|
||||||
},
|
},
|
||||||
"o": {
|
"o": {
|
||||||
"ribbingHeight": {
|
"ribbingHeight": {
|
||||||
|
|
|
@ -34,6 +34,8 @@ function hugoBack({
|
||||||
const neckOpening = new Path()
|
const neckOpening = new Path()
|
||||||
.move(points.cbNeck)
|
.move(points.cbNeck)
|
||||||
.curve(points.cbNeck, points.neckCp2, points.neck)
|
.curve(points.cbNeck, points.neckCp2, points.neck)
|
||||||
|
const length = neckOpening.length() * 2
|
||||||
|
store.set('front_neck_len', length)
|
||||||
points.raglanTipBack = neckOpening.shiftFractionAlong(0.7)
|
points.raglanTipBack = neckOpening.shiftFractionAlong(0.7)
|
||||||
const neckOpeningParts = neckOpening.split(points.raglanTipBack)
|
const neckOpeningParts = neckOpening.split(points.raglanTipBack)
|
||||||
// Paths
|
// Paths
|
||||||
|
|
|
@ -61,6 +61,8 @@ function hugoFront({
|
||||||
const neckOpening = new Path()
|
const neckOpening = new Path()
|
||||||
.move(points.cfNeck)
|
.move(points.cfNeck)
|
||||||
.curve(points.cfNeckCp1, points.neckCp2, points.neck)
|
.curve(points.cfNeckCp1, points.neckCp2, points.neck)
|
||||||
|
const length = neckOpening.length() * 2
|
||||||
|
store.set('back_neck_len', length)
|
||||||
points.raglanTipFront = neckOpening.shiftFractionAlong(0.8)
|
points.raglanTipFront = neckOpening.shiftFractionAlong(0.8)
|
||||||
const neckOpeningParts = neckOpening.split(points.raglanTipFront)
|
const neckOpeningParts = neckOpening.split(points.raglanTipFront)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
export const collarEase = 0.05
|
|
||||||
export const armholeDepthFactor = 0.5
|
export const armholeDepthFactor = 0.5
|
||||||
export const shoulderEase = 0
|
export const shoulderEase = 0
|
||||||
export const shoulderSlopeReduction = 0
|
export const shoulderSlopeReduction = 0
|
||||||
|
@ -14,3 +13,4 @@ export const lengthBonus = { pct: 10, min: 0, max: 20, menu: 'style' }
|
||||||
export const sleeveLengthBonus = { pct: 2, min: 0, max: 10, menu: 'style' }
|
export const sleeveLengthBonus = { pct: 2, min: 0, max: 10, menu: 'style' }
|
||||||
export const ribbingHeight = { pct: 10, min: 4, max: 20, menu: 'style' }
|
export const ribbingHeight = { pct: 10, min: 4, max: 20, menu: 'style' }
|
||||||
export const pocketWidth = { pct: 50, min: 35, max: 65, menu: 'style' }
|
export const pocketWidth = { pct: 50, min: 35, max: 65, menu: 'style' }
|
||||||
|
export const collarEase = { pct: 15, min: 0, max: 40, menu: 'fit' }
|
||||||
|
|
|
@ -17,6 +17,8 @@ function hugoSleeve({
|
||||||
options,
|
options,
|
||||||
measurements,
|
measurements,
|
||||||
macro,
|
macro,
|
||||||
|
log,
|
||||||
|
units,
|
||||||
part,
|
part,
|
||||||
}) {
|
}) {
|
||||||
// Top of raglan sleeve
|
// Top of raglan sleeve
|
||||||
|
@ -233,6 +235,46 @@ function hugoSleeve({
|
||||||
y: points.wristLeft.y + 15 + sa,
|
y: points.wristLeft.y + 15 + sa,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check neck opening size and warn if necessary.
|
||||||
|
*/
|
||||||
|
const sleeve_neck_len =
|
||||||
|
new Path()
|
||||||
|
.move(points.raglanTipBack)
|
||||||
|
.curve(points.raglanTipBackCp2, points.raglanTopCp1, points.raglanTop)
|
||||||
|
.curve(points.raglanTopCp2, points.raglanTipFrontCp1, points.raglanTipFront)
|
||||||
|
.length() * 2
|
||||||
|
|
||||||
|
const neck_opening = store.get('front_neck_len') + store.get('back_neck_len') + sleeve_neck_len
|
||||||
|
const diff = measurements.head - neck_opening
|
||||||
|
const discrepancy = diff / measurements.head
|
||||||
|
const warning_limit = 0.04
|
||||||
|
let label = ' bigger than '
|
||||||
|
if (diff > 0) label = ' smaller than '
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
': ' +
|
||||||
|
units(neck_opening) +
|
||||||
|
' neck opening is ' +
|
||||||
|
units(Math.abs(diff)) +
|
||||||
|
label +
|
||||||
|
' than ' +
|
||||||
|
units(measurements.head) +
|
||||||
|
' head circumference, with Collar Ease set to ' +
|
||||||
|
(options.collarEase * 100).toFixed(0) +
|
||||||
|
'%.'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (discrepancy > warning_limit) {
|
||||||
|
store.flag.warn({
|
||||||
|
msg: `hugo:neckCircumference`,
|
||||||
|
replace: {
|
||||||
|
opening: units(neck_opening),
|
||||||
|
head: units(measurements.head),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,10 @@ export const draftBarrelCuff = (part) => {
|
||||||
export const decorateBarrelCuff = (part) => {
|
export const decorateBarrelCuff = (part) => {
|
||||||
const { macro, store, snippets, Snippet, points, measurements, options, Point } = part.shorthand()
|
const { macro, store, snippets, Snippet, points, measurements, options, Point } = part.shorthand()
|
||||||
// Cutlist
|
// Cutlist
|
||||||
store.cutlist.setCut({ cut: 4, from: 'fabric' })
|
store.cutlist.setCut([
|
||||||
|
{ cut: 4, from: 'fabric' },
|
||||||
|
{ cut: 2, from: 'interfacing' },
|
||||||
|
])
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
points.title = new Point(points.bottomRight.x / 2, points.bottomRight.y / 2)
|
points.title = new Point(points.bottomRight.x / 2, points.bottomRight.y / 2)
|
||||||
|
@ -188,7 +191,10 @@ export const draftFrenchCuff = (part) => {
|
||||||
export const decorateFrenchCuff = (part) => {
|
export const decorateFrenchCuff = (part) => {
|
||||||
const { macro, store, snippets, Snippet, points, measurements, options, Point } = part.shorthand()
|
const { macro, store, snippets, Snippet, points, measurements, options, Point } = part.shorthand()
|
||||||
// Cutlist
|
// Cutlist
|
||||||
store.cutlist.setCut({ cut: 4, from: 'fabric' })
|
store.cutlist.setCut([
|
||||||
|
{ cut: 4, from: 'fabric' },
|
||||||
|
{ cut: 2, from: 'interfacing' },
|
||||||
|
])
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
points.title = new Point(points.bottomRight.x / 2, points.bottomRight.y / 2)
|
points.title = new Point(points.bottomRight.x / 2, points.bottomRight.y / 2)
|
||||||
|
|
|
@ -117,6 +117,18 @@
|
||||||
"centerBackDart": {
|
"centerBackDart": {
|
||||||
"t": "Center back dart",
|
"t": "Center back dart",
|
||||||
"d": "Whether or not to include a center back dart to fit a rounded back."
|
"d": "Whether or not to include a center back dart to fit a rounded back."
|
||||||
|
},
|
||||||
|
"legacyWaistHips": {
|
||||||
|
"t": "Legacy waist and hips widths",
|
||||||
|
"d": "Enable this option to use the legacy (v3) way to calculate the waist and hips widths (using chest circumference) rather than the new way (using the waist and hips measurements)."
|
||||||
|
},
|
||||||
|
"legacyWaistHipsNo": {
|
||||||
|
"t": "Calculate waist and hips widths the new way",
|
||||||
|
"d": "Uses the waist and hips measurements to calculate the waist and hips widths"
|
||||||
|
},
|
||||||
|
"legacyWaistHipsYes": {
|
||||||
|
"t": "Calculate waist and hips widths the legacy (v3) way",
|
||||||
|
"d": "Uses the chest measurement to approximate the waist and hips widths"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import { constructMainDart, shapeSideSeam, dartPath } from './shared.mjs'
|
import { constructMainDart, shapeSideSeam, dartPath } from './shared.mjs'
|
||||||
import { back as brianBack } from '@freesewing/brian'
|
import { back as brianBack } from '@freesewing/brian'
|
||||||
import { backInset, shoulderInset, neckInset, centerBackDart, backScyeDart } from './options.mjs'
|
import {
|
||||||
|
backInset,
|
||||||
|
shoulderInset,
|
||||||
|
neckInset,
|
||||||
|
centerBackDart,
|
||||||
|
backScyeDart,
|
||||||
|
legacyWaistHips,
|
||||||
|
} from './options.mjs'
|
||||||
import { hidePresets } from '@freesewing/core'
|
import { hidePresets } from '@freesewing/core'
|
||||||
|
|
||||||
function wahidBack({
|
function wahidBack({
|
||||||
|
@ -20,6 +27,13 @@ function wahidBack({
|
||||||
for (let i of Object.keys(paths)) delete paths[i]
|
for (let i of Object.keys(paths)) delete paths[i]
|
||||||
delete snippets.armholePitchNotch
|
delete snippets.armholePitchNotch
|
||||||
|
|
||||||
|
if (!options.legacyWaistHips) {
|
||||||
|
// Use actual measurements to set waist and hips points
|
||||||
|
points.waist = new Point((measurements.waist * (1 + options.waistEase)) / 4, points.cbWaist.y)
|
||||||
|
points.hips = new Point((measurements.hips * (1 + options.hipsEase)) / 4, points.cbHips.y)
|
||||||
|
points.hem = new Point(points.hips.x, points.cbHem.y)
|
||||||
|
}
|
||||||
|
|
||||||
// Back inset
|
// Back inset
|
||||||
let shoulderLen = points.shoulder.dist(points.neck)
|
let shoulderLen = points.shoulder.dist(points.neck)
|
||||||
let backInset = shoulderLen * options.backInset
|
let backInset = shoulderLen * options.backInset
|
||||||
|
@ -279,6 +293,7 @@ export const back = {
|
||||||
neckInset,
|
neckInset,
|
||||||
centerBackDart,
|
centerBackDart,
|
||||||
backScyeDart,
|
backScyeDart,
|
||||||
|
legacyWaistHips,
|
||||||
},
|
},
|
||||||
draft: wahidBack,
|
draft: wahidBack,
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import {
|
||||||
s3Armhole,
|
s3Armhole,
|
||||||
shoulderSlopeReduction,
|
shoulderSlopeReduction,
|
||||||
backNeckCutout,
|
backNeckCutout,
|
||||||
|
legacyWaistHips,
|
||||||
} from './options.mjs'
|
} from './options.mjs'
|
||||||
|
|
||||||
function wahidFront({
|
function wahidFront({
|
||||||
|
@ -51,6 +52,14 @@ function wahidFront({
|
||||||
// Cleanup from Brian
|
// Cleanup from Brian
|
||||||
for (let i of Object.keys(paths)) delete paths[i]
|
for (let i of Object.keys(paths)) delete paths[i]
|
||||||
delete snippets.armholePitchNotch
|
delete snippets.armholePitchNotch
|
||||||
|
|
||||||
|
if (!options.legacyWaistHips) {
|
||||||
|
// Use actual measurements to set waist and hips points
|
||||||
|
points.waist = new Point((measurements.waist * (1 + options.waistEase)) / 4, points.cfWaist.y)
|
||||||
|
points.hips = new Point((measurements.hips * (1 + options.hipsEase)) / 4, points.cfHips.y)
|
||||||
|
points.hem = new Point(points.hips.x, points.cfHem.y)
|
||||||
|
}
|
||||||
|
|
||||||
// Neck cutout
|
// Neck cutout
|
||||||
points.closureTop = new Point(
|
points.closureTop = new Point(
|
||||||
measurements.chest * options.frontOverlap * -1,
|
measurements.chest * options.frontOverlap * -1,
|
||||||
|
@ -176,15 +185,31 @@ function wahidFront({
|
||||||
points.dartHipLeft,
|
points.dartHipLeft,
|
||||||
points.pocketTopMid.y + pwvh
|
points.pocketTopMid.y + pwvh
|
||||||
)
|
)
|
||||||
points.pocketTopLeft = points.pocketTopMidLeft.shift(180 + options.pocketAngle, pw / 2)
|
// The pocket can start out offset from the horizontal/vertical.
|
||||||
points.pocketBottomLeft = points.pocketTopLeft.shift(options.pocketAngle - 90, pwh)
|
const startingAngleOffset = points.pocketBottomMidLeft.angle(points.pocketTopMidLeft) - 90
|
||||||
|
points.pocketTopLeft = points.pocketTopMidLeft.shift(
|
||||||
|
180 + options.pocketAngle + startingAngleOffset,
|
||||||
|
pw / 2
|
||||||
|
)
|
||||||
|
points.pocketBottomLeft = points.pocketTopLeft.shift(
|
||||||
|
options.pocketAngle - 90 + startingAngleOffset,
|
||||||
|
pwh
|
||||||
|
)
|
||||||
points.pocketTopMidRight = points.pocketTopMidLeft.flipX(points.pocketTopMid)
|
points.pocketTopMidRight = points.pocketTopMidLeft.flipX(points.pocketTopMid)
|
||||||
points.pocketBottomMidRight = points.pocketBottomMidLeft.flipX(points.pocketTopMid)
|
points.pocketBottomMidRight = points.pocketBottomMidLeft.flipX(points.pocketTopMid)
|
||||||
points.pocketTopRight = points.pocketTopMidRight.shift(options.pocketAngle, pw / 2)
|
points.pocketTopRight = points.pocketTopMidRight.shift(
|
||||||
points.pocketBottomRight = points.pocketTopRight.shift(options.pocketAngle - 90, pwh)
|
options.pocketAngle - startingAngleOffset,
|
||||||
|
pw / 2
|
||||||
|
)
|
||||||
|
points.pocketBottomRight = points.pocketTopRight.shift(
|
||||||
|
options.pocketAngle - 90 - startingAngleOffset,
|
||||||
|
pwh
|
||||||
|
)
|
||||||
// Store pocket bag length
|
// Store pocket bag length
|
||||||
store.set('pocketBagLength', points.pocketTopMid.dy(points.cfHem) * 0.75)
|
store.set('pocketBagLength', points.pocketTopMid.dy(points.cfHem) * 0.75)
|
||||||
if (options.frontScyeDart) {
|
if (options.frontScyeDart) {
|
||||||
|
// Save original armhole width so we can restore it later
|
||||||
|
const original_chest_width = points.cfArmhole.dist(points.armhole)
|
||||||
// Front scye dart
|
// Front scye dart
|
||||||
points._dartWidth = points.dartTop.shiftFractionTowards(
|
points._dartWidth = points.dartTop.shiftFractionTowards(
|
||||||
points.armholeHollow.rotate(options.frontScyeDart, points.dartTop),
|
points.armholeHollow.rotate(options.frontScyeDart, points.dartTop),
|
||||||
|
@ -230,6 +255,10 @@ function wahidFront({
|
||||||
if (typeof points[p] !== 'undefined')
|
if (typeof points[p] !== 'undefined')
|
||||||
points[p] = points[p].rotate(options.frontScyeDart, points.dartTop)
|
points[p] = points[p].rotate(options.frontScyeDart, points.dartTop)
|
||||||
}
|
}
|
||||||
|
if (!options.legacyWaistHips) {
|
||||||
|
// Set armhole back to original width
|
||||||
|
points.armhole = points.cfArmhole.shiftTowards(points.armhole, original_chest_width)
|
||||||
|
}
|
||||||
points.armholeHollowCp1 = points.armholeHollowCp2.rotate(180, points.armholeHollow)
|
points.armholeHollowCp1 = points.armholeHollowCp2.rotate(180, points.armholeHollow)
|
||||||
}
|
}
|
||||||
// Facing/Lining boundary (flb)
|
// Facing/Lining boundary (flb)
|
||||||
|
@ -314,6 +343,7 @@ function wahidFront({
|
||||||
*/
|
*/
|
||||||
// Cutlist
|
// Cutlist
|
||||||
store.cutlist.setCut({ cut: 2, from: 'fabric' })
|
store.cutlist.setCut({ cut: 2, from: 'fabric' })
|
||||||
|
store.cutlist.addCut({ cut: 2, from: 'interfacing' })
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
points.button1 = new Point(0, points.closureTop.y + 10)
|
points.button1 = new Point(0, points.closureTop.y + 10)
|
||||||
|
@ -561,6 +591,7 @@ export const front = {
|
||||||
s3Armhole,
|
s3Armhole,
|
||||||
shoulderSlopeReduction,
|
shoulderSlopeReduction,
|
||||||
backNeckCutout,
|
backNeckCutout,
|
||||||
|
legacyWaistHips,
|
||||||
},
|
},
|
||||||
draft: wahidFront,
|
draft: wahidFront,
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ export const shoulderInset = { pct: 10, min: 0, max: 20, menu: 'advanced' }
|
||||||
export const neckInset = { pct: 5, min: 0, max: 10, menu: 'advanced' }
|
export const neckInset = { pct: 5, min: 0, max: 10, menu: 'advanced' }
|
||||||
export const pocketAngle = { deg: 5, min: 0, max: 5, menu: 'advanced' }
|
export const pocketAngle = { deg: 5, min: 0, max: 5, menu: 'advanced' }
|
||||||
export const shoulderSlopeReduction = { pct: 0, min: 0, max: 80, menu: 'advanced' }
|
export const shoulderSlopeReduction = { pct: 0, min: 0, max: 80, menu: 'advanced' }
|
||||||
|
export const legacyWaistHips = { bool: false, menu: 'advanced' }
|
||||||
|
|
||||||
// Hide inherited options
|
// Hide inherited options
|
||||||
export const bicepsEase = 0.15
|
export const bicepsEase = 0.15
|
||||||
|
|
|
@ -16,6 +16,22 @@ export const constructMainDart = (part) => {
|
||||||
store.set('wr12', wr12)
|
store.set('wr12', wr12)
|
||||||
store.set('hr12', hr12)
|
store.set('hr12', hr12)
|
||||||
|
|
||||||
|
if (!options.legacyWaistHips) {
|
||||||
|
// Use largest chest-or-hips measurement to determine reduction
|
||||||
|
const largest_measurement = chest >= hips ? chest : hips
|
||||||
|
reduce.waist = largest_measurement - waist
|
||||||
|
reduce.hips = largest_measurement - hips
|
||||||
|
if (reduce.hips < 0) reduce.hips = 0
|
||||||
|
if (reduce.waist < 0) reduce.waist = 0
|
||||||
|
// Use a different reduction factor
|
||||||
|
const reduction_factor = 15
|
||||||
|
wr12 = reduce.waist / reduction_factor
|
||||||
|
hr12 = reduce.hips / reduction_factor
|
||||||
|
// Shift side seam to other direction by total amount added to dart
|
||||||
|
store.set('wr12', wr12 * -2)
|
||||||
|
store.set('hr12', hr12 * -2)
|
||||||
|
}
|
||||||
|
|
||||||
points.dartWaistCenter = new Point(points.armhole.x / 2, points.waist.y)
|
points.dartWaistCenter = new Point(points.armhole.x / 2, points.waist.y)
|
||||||
points.dartWaistRight = points.dartWaistCenter.shift(0, wr12)
|
points.dartWaistRight = points.dartWaistCenter.shift(0, wr12)
|
||||||
points.dartWaistLeft = points.dartWaistCenter.shift(180, wr12)
|
points.dartWaistLeft = points.dartWaistCenter.shift(180, wr12)
|
||||||
|
|
|
@ -264,7 +264,12 @@ export const BookmarkButton = ({ slug, type, title }) => {
|
||||||
className={`tw:daisy-btn tw:daisy-btn-secondary tw:daisy-btn-outline ${horFlexClasses}`}
|
className={`tw:daisy-btn tw:daisy-btn-secondary tw:daisy-btn-outline ${horFlexClasses}`}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setModal(
|
setModal(
|
||||||
<ModalWrapper flex="col" justify="top lg:justify-center" slideFrom="right">
|
<ModalWrapper
|
||||||
|
flex="col"
|
||||||
|
justify="top lg:justify-center"
|
||||||
|
slideFrom="right"
|
||||||
|
keepOpenOnClick="true"
|
||||||
|
>
|
||||||
<CreateBookmark {...{ type, title, slug }} />
|
<CreateBookmark {...{ type, title, slug }} />
|
||||||
</ModalWrapper>
|
</ModalWrapper>
|
||||||
)
|
)
|
||||||
|
@ -292,13 +297,12 @@ const CreateBookmark = ({ type, title, slug }) => {
|
||||||
const { setLoadingStatus } = useContext(LoadingStatusContext)
|
const { setLoadingStatus } = useContext(LoadingStatusContext)
|
||||||
const { setModal } = useContext(ModalContext)
|
const { setModal } = useContext(ModalContext)
|
||||||
|
|
||||||
const url = slug.toLowerCase().slice(0,4) === 'http'
|
const url = slug.toLowerCase().slice(0, 4) === 'http' ? slug : `/${slug}`
|
||||||
? slug
|
|
||||||
: `/${slug}`
|
|
||||||
|
|
||||||
const bookmark = async (evt) => {
|
const bookmark = async (evt) => {
|
||||||
evt.stopPropagation()
|
evt.stopPropagation()
|
||||||
setLoadingStatus([true, 'Contacting backend'])
|
setLoadingStatus([true, 'Contacting backend'])
|
||||||
|
let title = name
|
||||||
const [status] = await backend.createBookmark({ type, title, url })
|
const [status] = await backend.createBookmark({ type, title, url })
|
||||||
if (status === 201) {
|
if (status === 201) {
|
||||||
setLoadingStatus([true, 'Bookmark created', true, true])
|
setLoadingStatus([true, 'Bookmark created', true, true])
|
||||||
|
|
|
@ -118,7 +118,7 @@ export const Pattern = ({ id, Link }) => {
|
||||||
delete data.data
|
delete data.data
|
||||||
delete data.userId
|
delete data.userId
|
||||||
delete data.img
|
delete data.img
|
||||||
data.settings = JSON.parse(data.settings)
|
data.name += ' (clone)'
|
||||||
const [status, body] = await backend.createPattern(data)
|
const [status, body] = await backend.createPattern(data)
|
||||||
if (status === 201 && body.result === 'created') {
|
if (status === 201 && body.result === 'created') {
|
||||||
setLoadingStatus([true, 'Loading newly created pattern', true, true])
|
setLoadingStatus([true, 'Loading newly created pattern', true, true])
|
||||||
|
|
|
@ -278,19 +278,19 @@ const DesignCard = ({ name, lineDrawing = false, linkTo, Link, onClick }) => {
|
||||||
const exampleImageUrl = examples.href[name] ? examples.href[name] : noExample
|
const exampleImageUrl = examples.href[name] ? examples.href[name] : noExample
|
||||||
const bg = { aspectRatio: '1/1.4' }
|
const bg = { aspectRatio: '1/1.4' }
|
||||||
if (!lineDrawing) {
|
if (!lineDrawing) {
|
||||||
bg.backgroundImage = `url(${exampleImageUrl}`
|
bg.backgroundImage = `url(${exampleImageUrl})`
|
||||||
bg.backgroundSize = 'cover'
|
bg.backgroundSize = 'cover'
|
||||||
bg.backgroundPosition = 'center center'
|
bg.backgroundPosition = 'center center'
|
||||||
}
|
}
|
||||||
|
|
||||||
const inner = (
|
const inner = (
|
||||||
<div
|
<div
|
||||||
className={`tw:flex tw:flex-col tw:flex-nowrap tw:items-start tw:justify-between tw:gap-2 tw:border-neutral-500 tw:group-hover:border-secondary
|
className={`tw:flex tw:flex-col tw:flex-nowrap tw:justify-between tw:gap-2 tw:border-neutral-500 tw:group-hover:border-secondary
|
||||||
tw:w-full tw:h-full tw:border tw:border-2 tw:border-solid tw:p-0 tw:relative tw:rounded-lg tw:rounded-lg`}
|
tw:w-full tw:h-full tw:border tw:border-2 tw:border-solid tw:p-0 tw:relative tw:rounded-lg`}
|
||||||
style={bg}
|
style={bg}
|
||||||
>
|
>
|
||||||
<h5
|
<h5
|
||||||
className={`tw:text-center tw:py-2 tw:px-4 tw:rounded-t tw:m-0 tw:w-full tw:group-hover:no-underline tw:group-hover:bg-secondary/80 tw:group-hover:text-secondary-content
|
className={`tw:text-center tw:py-2 tw:px-4 tw:rounded-t tw:m-0 tw:group-hover:no-underline tw:group-hover:bg-secondary/80 tw:group-hover:text-secondary-content
|
||||||
${lineDrawing ? '' : 'tw:bg-neutral/80'}`}
|
${lineDrawing ? '' : 'tw:bg-neutral/80'}`}
|
||||||
>
|
>
|
||||||
<span className={lineDrawing ? 'tw:text-base-100-content' : 'tw:text-neutral-content'}>
|
<span className={lineDrawing ? 'tw:text-base-100-content' : 'tw:text-neutral-content'}>
|
||||||
|
@ -298,14 +298,14 @@ const DesignCard = ({ name, lineDrawing = false, linkTo, Link, onClick }) => {
|
||||||
</span>
|
</span>
|
||||||
</h5>
|
</h5>
|
||||||
{lineDrawing ? (
|
{lineDrawing ? (
|
||||||
<div className="tw:grow tw:w-full tw:h-auto tw:square tw:text-center">
|
<div className="tw:flex-auto tw:flex tw:justify-center">
|
||||||
<LineDrawing className="tw:w-5/6 tw:m-auto tw:my-0 tw:text-base-content" />
|
<LineDrawing className="tw:w-5/6 tw:text-base-content" />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className={`tw:flex tw:flex-row tw:items-center tw:justify-center tw:py-1 tw:px-2 tw:rounded-b tw:m-0 tw:w-full
|
className={`tw:flex tw:flex-row tw:items-center tw:justify-center tw:py-1 tw:px-2 tw:rounded-b tw:m-0
|
||||||
${lineDrawing ? '' : `tw:text-neutral-content`}`}
|
${lineDrawing ? '' : `tw:text-neutral-content`}`}
|
||||||
>
|
>
|
||||||
<Difficulty score={about[name].difficulty} className="tw:group-hover:text-secondary" />
|
<Difficulty score={about[name].difficulty} className="tw:group-hover:text-secondary" />
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { ViewIcon, viewLabels } from './views/index.mjs'
|
||||||
import { Tooltip } from './Tooltip.mjs'
|
import { Tooltip } from './Tooltip.mjs'
|
||||||
import {
|
import {
|
||||||
AsideIcon,
|
AsideIcon,
|
||||||
|
CompactIcon,
|
||||||
DetailIcon,
|
DetailIcon,
|
||||||
ExpandIcon,
|
ExpandIcon,
|
||||||
ExportIcon,
|
ExportIcon,
|
||||||
|
@ -241,7 +242,8 @@ export const HeaderMenuDraftViewUiPreferences = (props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HeaderMenuDraftViewFlags = (props) => {
|
export const HeaderMenuDraftViewFlags = (props) => {
|
||||||
const count = Object.keys(flattenFlags(props.flags)).length
|
const flatFlags = flattenFlags(props.flags)
|
||||||
|
const count = Object.keys(flatFlags).length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderMenuDropdown
|
<HeaderMenuDropdown
|
||||||
|
@ -253,7 +255,12 @@ export const HeaderMenuDraftViewFlags = (props) => {
|
||||||
<HeaderMenuIcon name="flag" extraClasses="tw:text-secondary" />
|
<HeaderMenuIcon name="flag" extraClasses="tw:text-secondary" />
|
||||||
<span className="tw:hidden tw:lg:inline">
|
<span className="tw:hidden tw:lg:inline">
|
||||||
Flags
|
Flags
|
||||||
<span>({count})</span>
|
<NumberBadge
|
||||||
|
value={count}
|
||||||
|
color={
|
||||||
|
Object.values(flatFlags).some((it) => it.type === 'error') ? 'error' : 'secondary'
|
||||||
|
}
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
@ -263,6 +270,17 @@ export const HeaderMenuDraftViewFlags = (props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NumberBadge = ({ value, color = 'secondary', className = '' }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`tw:ml-2 tw:inline-flex tw:items-center tw:justify-center tw:rounded-full tw:bg-${color} tw:text-${color}-content tw:text-xs tw:w-5 tw:h-5 tw:leading-none tw:font-semibold ${className}`}
|
||||||
|
style={{ lineHeight: '1rem' }}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export const HeaderMenuDraftViewIcons = (props) => {
|
export const HeaderMenuDraftViewIcons = (props) => {
|
||||||
const { update, state } = props
|
const { update, state } = props
|
||||||
const { settings = {} } = state // Guard against undefined settings
|
const { settings = {} } = state // Guard against undefined settings
|
||||||
|
@ -302,7 +320,7 @@ export const HeaderMenuDraftViewIcons = (props) => {
|
||||||
tooltip="Switches Units between metric and imperial (see Core Settings)"
|
tooltip="Switches Units between metric and imperial (see Core Settings)"
|
||||||
>
|
>
|
||||||
<UnitsIcon
|
<UnitsIcon
|
||||||
className={`${size} ${settings.units === accountUnits ? style.dflt : style.custom}`}
|
className={`${size} ${settings.units === accountUnits || typeof settings.units === 'undefined' ? style.dflt : style.custom}`}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -336,9 +354,11 @@ export const HeaderMenuDraftViewIcons = (props) => {
|
||||||
}
|
}
|
||||||
tooltip="Turns Expand on or off (see Core Settings)"
|
tooltip="Turns Expand on or off (see Core Settings)"
|
||||||
>
|
>
|
||||||
<ExpandIcon
|
{[false, 0, '0'].includes(settings.expand) ? (
|
||||||
className={`${size} ${[false, 0, '0'].includes(settings.expand) ? style.custom : style.dflt}`}
|
<CompactIcon className={`${size} ${style.custom}`} />
|
||||||
/>
|
) : (
|
||||||
|
<ExpandIcon className={`${size} ${style.dflt}`} />
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
<HeaderMenuIconSpacer />
|
<HeaderMenuIconSpacer />
|
||||||
|
|
|
@ -130,10 +130,15 @@ export const BookmarkedSetPicker = ({
|
||||||
const [status, body] = await backend.getBookmarks()
|
const [status, body] = await backend.getBookmarks()
|
||||||
const loadedSets = {}
|
const loadedSets = {}
|
||||||
if (status === 200 && body.result === 'success') {
|
if (status === 200 && body.result === 'success') {
|
||||||
|
const setsRE = /\/set(\?id=|s\/)(\d+)$/
|
||||||
|
const unique_ids = new Set()
|
||||||
for (const bookmark of body.bookmarks.filter((bookmark) => bookmark.type === 'set')) {
|
for (const bookmark of body.bookmarks.filter((bookmark) => bookmark.type === 'set')) {
|
||||||
let set
|
const match = bookmark.url.match(setsRE)
|
||||||
|
if (match) unique_ids.add(match[2])
|
||||||
|
}
|
||||||
|
for (const id of unique_ids) {
|
||||||
try {
|
try {
|
||||||
const [status, body] = await backend.getSet(bookmark.url.slice(6))
|
const [status, body] = await backend.getSet(id)
|
||||||
if (status === 200 && body.result === 'success') {
|
if (status === 200 && body.result === 'success') {
|
||||||
const [hasMeasies] = hasRequiredMeasurements(Design, body.set.measies)
|
const [hasMeasies] = hasRequiredMeasurements(Design, body.set.measies)
|
||||||
loadedSets[body.set.id] = { ...body.set, hasMeasies }
|
loadedSets[body.set.id] = { ...body.set, hasMeasies }
|
||||||
|
|
|
@ -216,6 +216,7 @@ export const MenuItemGroup = ({
|
||||||
config={item}
|
config={item}
|
||||||
changed={menuValueWasChanged(currentValues[itemName], item)}
|
changed={menuValueWasChanged(currentValues[itemName], item)}
|
||||||
Design={Design}
|
Design={Design}
|
||||||
|
units={state?.settings?.units}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
|
|
|
@ -149,7 +149,9 @@ export const MenuListInput = ({
|
||||||
: 'tw:flex-col tw:items-start'
|
: 'tw:flex-col tw:items-start'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="tw:font-semibold">{config.choiceTitles[entry]}</div>
|
<div className="tw:font-semibold">
|
||||||
|
{config.doNotTranslate ? entry : config.choiceTitles[entry]}
|
||||||
|
</div>
|
||||||
{compact || !config.choiceDescriptions ? null : (
|
{compact || !config.choiceDescriptions ? null : (
|
||||||
<div
|
<div
|
||||||
className={`${config.dense ? 'tw:text-sm tw:leading-5 tw:py-1' : 'tw:text-base'} tw:font-normal`}
|
className={`${config.dense ? 'tw:text-sm tw:leading-5 tw:py-1' : 'tw:text-base'} tw:font-normal`}
|
||||||
|
@ -203,12 +205,18 @@ export const MenuMmInput = (props) => {
|
||||||
/*
|
/*
|
||||||
* Set a default step that matches the unit.
|
* Set a default step that matches the unit.
|
||||||
*
|
*
|
||||||
* Note that we could try to use something like 1.5875 for imperial to move in steps of 1/16 inches,
|
* Imperial:
|
||||||
* but we round the mm values to two digits in the options, which would accumulate rounding errors.
|
* mm, inch, decimal digits precision needed:
|
||||||
*
|
* 1.27 mm, 0.1 in, 2 digits
|
||||||
* Because of this, we use 10ths of inches instead of 16ths of inches.
|
* 3.175 mm, 1/8 in, 3 digits
|
||||||
|
* 1.5875 mm, 1/16 in, 4 digits
|
||||||
|
* 0.79375 mm, 1/32 in, 5 digits
|
||||||
|
* We previously rounded mm values to 2 digits in the options and used
|
||||||
|
* a 1.27 mm (1/10 in) step because precision didn't support 1/16 in
|
||||||
|
* or 1/32 in steps.
|
||||||
|
* We now round mm values to 4 digits and use a 1.5875 mm (1/16 in.) step.
|
||||||
*/
|
*/
|
||||||
const defaultStep = imperial ? 1.27 : 1 // mm
|
const defaultStep = imperial ? 1.5875 : 1 // mm
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuSliderInput
|
<MenuSliderInput
|
||||||
|
|
|
@ -88,7 +88,7 @@ const SampleOptionButton = ({ name, i18n, update }) => (
|
||||||
onClick={() => update.settings('sample', { type: 'option', option: name })}
|
onClick={() => update.settings('sample', { type: 'option', option: name })}
|
||||||
>
|
>
|
||||||
<BeakerIcon className="tw:w-5 tw:h-5" />
|
<BeakerIcon className="tw:w-5 tw:h-5" />
|
||||||
<span>{i18n.en.o[name].t}</span>
|
<span>{i18n.en?.o[name]?.t ?? name}</span>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ export const MenuListValue = ({ current, config, changed }) => {
|
||||||
else if (val) key = <BoolYesIcon />
|
else if (val) key = <BoolYesIcon />
|
||||||
else key = <BoolNoIcon />
|
else key = <BoolNoIcon />
|
||||||
|
|
||||||
const translated = config.doNotTranslate || key
|
const translated = config.doNotTranslate ? val : key
|
||||||
|
|
||||||
return <MenuHighlightValue changed={changed}>{translated}</MenuHighlightValue>
|
return <MenuHighlightValue changed={changed}>{translated}</MenuHighlightValue>
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ export const MenuMmValue = ({ current, config, units, changed }) => (
|
||||||
* Displays the current percentage value, and the absolute value if configured
|
* Displays the current percentage value, and the absolute value if configured
|
||||||
*/
|
*/
|
||||||
export const MenuPctOptionValue = ({ config, current, settings, changed, patternConfig }) => {
|
export const MenuPctOptionValue = ({ config, current, settings, changed, patternConfig }) => {
|
||||||
const val = changed ? current : config.pct / 100
|
const val = changed ? current : config.dflt
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuHighlightValue changed={changed}>
|
<MenuHighlightValue changed={changed}>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Dependencies
|
// Dependencies
|
||||||
import { linkClasses } from '@freesewing/utils'
|
import { linkClasses, capitalize } from '@freesewing/utils'
|
||||||
// Hooks
|
// Hooks
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
// Components
|
// Components
|
||||||
|
@ -20,7 +20,22 @@ export const DocsView = ({ state, config, update }) => {
|
||||||
<>
|
<>
|
||||||
<HeaderMenu state={state} {...{ config, update }} />
|
<HeaderMenu state={state} {...{ config, update }} />
|
||||||
<div className="tw:m-auto tw:mt-8 tw:max-w-2xl tw:px-4 tw:mb-8">
|
<div className="tw:m-auto tw:mt-8 tw:max-w-2xl tw:px-4 tw:mb-8">
|
||||||
<H1>Documenation</H1>
|
<H1>Documentation</H1>
|
||||||
|
{state?.design ? (
|
||||||
|
<Popout link>
|
||||||
|
<H5>Design Documentation</H5>
|
||||||
|
<p className="tw:text-lg">
|
||||||
|
You can find documentation for the {capitalize(state.design)} design at:
|
||||||
|
<br />
|
||||||
|
<b>
|
||||||
|
<a
|
||||||
|
className={linkClasses}
|
||||||
|
href={`https://freesewing.eu/docs/designs/${state.design}`}
|
||||||
|
>{`FreeSewing.eu/docs/designs/${state.design}`}</a>
|
||||||
|
</b>
|
||||||
|
</p>
|
||||||
|
</Popout>
|
||||||
|
) : null}
|
||||||
<Popout link>
|
<Popout link>
|
||||||
<H5>Understanding the FreeSewing Pattern Editor</H5>
|
<H5>Understanding the FreeSewing Pattern Editor</H5>
|
||||||
<p className="tw:text-lg">
|
<p className="tw:text-lg">
|
||||||
|
@ -29,8 +44,8 @@ export const DocsView = ({ state, config, update }) => {
|
||||||
<b>
|
<b>
|
||||||
<a
|
<a
|
||||||
className={linkClasses}
|
className={linkClasses}
|
||||||
href="https://freesewing.org/docs/about/site/editor"
|
href="https://freesewing.eu/docs/about/editor"
|
||||||
>{`FreeSewing.org/docs/about/editor`}</a>
|
>{`FreeSewing.eu/docs/about/editor`}</a>
|
||||||
</b>
|
</b>
|
||||||
</p>
|
</p>
|
||||||
</Popout>
|
</Popout>
|
||||||
|
|
|
@ -43,7 +43,7 @@ export const TestView = ({ Design, state, update, config }) => {
|
||||||
if (missingMeasurements(state)) return <Null />
|
if (missingMeasurements(state)) return <Null />
|
||||||
|
|
||||||
const { settings } = state
|
const { settings } = state
|
||||||
if (settings.sample) {
|
if (settings?.sample) {
|
||||||
/*
|
/*
|
||||||
* When testing/sampling one design, and then switching the editor to a different design,
|
* When testing/sampling one design, and then switching the editor to a different design,
|
||||||
* we run the risk that settings.sample holds invalid configuration. Like testing an unused
|
* we run the risk that settings.sample holds invalid configuration. Like testing an unused
|
||||||
|
|
|
@ -158,7 +158,9 @@ export const handleExport = async ({
|
||||||
workerArgs.strings.setName = settings?.metadata?.setName
|
workerArgs.strings.setName = settings?.metadata?.setName
|
||||||
? settings.metadata.setName
|
? settings.metadata.setName
|
||||||
: 'ephemeral'
|
: 'ephemeral'
|
||||||
workerArgs.strings.yaml = yaml.dump(settings)
|
const settingsWithoutLayout = structuredClone(settings)
|
||||||
|
delete settingsWithoutLayout.layout
|
||||||
|
workerArgs.strings.yaml = yaml.dump(settingsWithoutLayout)
|
||||||
workerArgs.strings.version = store?.data?.version ? store.data.version : ''
|
workerArgs.strings.version = store?.data?.version ? store.data.version : ''
|
||||||
const notes = store?.plugins?.['plugin-annotations']?.flags?.note
|
const notes = store?.plugins?.['plugin-annotations']?.flags?.note
|
||||||
? store?.plugins?.['plugin-annotations']?.flags?.note
|
? store?.plugins?.['plugin-annotations']?.flags?.note
|
||||||
|
@ -190,9 +192,9 @@ const flagsToString = (flags, mustache, t) => {
|
||||||
let first = true
|
let first = true
|
||||||
let string = ''
|
let string = ''
|
||||||
for (const flag of Object.values(flags)) {
|
for (const flag of Object.values(flags)) {
|
||||||
let title = flag.replace ? mustache.render(flag.title, flag.replace) : flag.title
|
let title = flag.replace ? mustache.render(t(flag.title), flag.replace) : t(flag.title)
|
||||||
title = he.decode(title)
|
title = he.decode(title)
|
||||||
let desc = flag.replace ? mustache.render(flag.desc, flag.replace) : flag.desc
|
let desc = flag.replace ? mustache.render(t(flag.desc), flag.replace) : t(flag.desc)
|
||||||
desc = desc.replaceAll('\n\n', '\n')
|
desc = desc.replaceAll('\n\n', '\n')
|
||||||
desc = desc.replaceAll('\n', ' ')
|
desc = desc.replaceAll('\n', ' ')
|
||||||
desc = he.decode(desc)
|
desc = he.decode(desc)
|
||||||
|
|
|
@ -20,7 +20,8 @@ const defaultPrintSettings = (units) => ({
|
||||||
size: units === 'imperial' ? 'letter' : 'a4',
|
size: units === 'imperial' ? 'letter' : 'a4',
|
||||||
orientation: 'portrait',
|
orientation: 'portrait',
|
||||||
margin: units === 'imperial' ? 12.7 : 10,
|
margin: units === 'imperial' ? 12.7 : 10,
|
||||||
coverPage: true,
|
coverPage: 1,
|
||||||
|
iconSize: 0.5,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function menuLayoutSettingsStructure(units) {
|
export function menuLayoutSettingsStructure(units) {
|
||||||
|
@ -76,6 +77,7 @@ export function menuLayoutSettingsStructure(units) {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
icon: PageOrientationIcon,
|
icon: PageOrientationIcon,
|
||||||
|
dflt: defaults.orientation,
|
||||||
},
|
},
|
||||||
margin: {
|
margin: {
|
||||||
dense: true,
|
dense: true,
|
||||||
|
@ -98,7 +100,7 @@ export function menuLayoutSettingsStructure(units) {
|
||||||
0: 'Do not include a cover page',
|
0: 'Do not include a cover page',
|
||||||
1: 'Include a cover page',
|
1: 'Include a cover page',
|
||||||
},
|
},
|
||||||
dflt: 0,
|
dflt: defaults.coverPage,
|
||||||
},
|
},
|
||||||
iconSize: {
|
iconSize: {
|
||||||
dense: true,
|
dense: true,
|
||||||
|
@ -108,7 +110,7 @@ export function menuLayoutSettingsStructure(units) {
|
||||||
about:
|
about:
|
||||||
'Controls the size of the icons that allow you to rotate/flip individual pattern parts',
|
'Controls the size of the icons that allow you to rotate/flip individual pattern parts',
|
||||||
min: 10,
|
min: 10,
|
||||||
dflt: 0.5,
|
dflt: defaults.iconSize,
|
||||||
step: 1,
|
step: 1,
|
||||||
max: 200,
|
max: 200,
|
||||||
},
|
},
|
||||||
|
|
|
@ -333,6 +333,25 @@ export const CodeIcon = (props) => (
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An SVG icon that looks like arrows pointing inwards
|
||||||
|
*
|
||||||
|
* @component
|
||||||
|
* @param {object} props - All component props
|
||||||
|
* @param {boolean} [props.className = 'tw:m-6 tw:h-6'] - The CSS classes to apply to the SVG element
|
||||||
|
* @param {number} [props.stroke = 2] - The stroke width
|
||||||
|
* @param {JSX.Element} props.children - The component childer, the inner content of the SVG tag
|
||||||
|
* @param {boolean} [props.fill = false] - Whether or not to fill the icon
|
||||||
|
* @param {number} [props.fillOpacity = 1] - The fillOpacity to apply
|
||||||
|
* @param {string} [props.dashArray = null] - An optional stroke dashArray to apply to the stroke
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
*/
|
||||||
|
export const CompactIcon = (props) => (
|
||||||
|
<IconWrapper {...props}>
|
||||||
|
<path d="m15 15v4.5m0-4.5h4.5m-15.8-11.3 5.25 5.25m6 0v-4.5m0 4.5h4.5m-15.8 11.3 5.25-5.25h-4.5m4.5 0v4.5m11.3-15.8-5.25 5.25m-6 0h-4.5m4.5 0v-4.5m11.3 15.8-5.25-5.25" />
|
||||||
|
</IconWrapper>
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An SVG icon that looks like FIXME
|
* An SVG icon that looks like FIXME
|
||||||
*
|
*
|
||||||
|
@ -2106,4 +2125,3 @@ export const ZoomOutIcon = (props) => (
|
||||||
<path d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607ZM13.5 10.5h-6" />
|
<path d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607ZM13.5 10.5h-6" />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ export const translateStrings = (list, translations = {}) => {
|
||||||
else if (string) {
|
else if (string) {
|
||||||
if (translations[string]) {
|
if (translations[string]) {
|
||||||
translated += `${translations[string]}`.replace(/"/g, '"') + ' '
|
translated += `${translations[string]}`.replace(/"/g, '"') + ' '
|
||||||
} else translated += `${string}`
|
} else translated += `${string}` + ' '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ export const PointXray = ({
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
></circle>
|
></circle>
|
||||||
<text x={point.x + 3} y={point.y} className="text-sm">
|
<text x={point.x + 3} y={point.y} className="text-sm tw:pointer-events-none">
|
||||||
<tspan>{pointName}</tspan>
|
<tspan>{pointName}</tspan>
|
||||||
<tspan x={point.x + 3} dy={5}>
|
<tspan x={point.x + 3} dy={5}>
|
||||||
{round(point.x)},{round(point.y)}
|
{round(point.x)},{round(point.y)}
|
||||||
|
|
|
@ -2,6 +2,25 @@ import { themes as prismThemes } from 'prism-react-renderer'
|
||||||
import { docusaurusPlugins } from './plugins/index.mjs'
|
import { docusaurusPlugins } from './plugins/index.mjs'
|
||||||
import smartypants from 'remark-smartypants'
|
import smartypants from 'remark-smartypants'
|
||||||
|
|
||||||
|
function customizeSidebar(items) {
|
||||||
|
// Filter out submenus in Your Measurements Sets and Your Patterns
|
||||||
|
for (const item in items) {
|
||||||
|
if (items[item].label === 'Account') {
|
||||||
|
for (const design in items[item].items) {
|
||||||
|
for (const subpage in items[item].items[design].items) {
|
||||||
|
if (
|
||||||
|
items[item].items[design].items[subpage].label === 'Your Measurements Sets' ||
|
||||||
|
items[item].items[design].items[subpage].label === 'Your Patterns'
|
||||||
|
) {
|
||||||
|
items[item].items[design].items[subpage].items = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
title: 'FreeSewing Studio',
|
title: 'FreeSewing Studio',
|
||||||
tagline: 'FreeSewing for Designers',
|
tagline: 'FreeSewing for Designers',
|
||||||
|
@ -28,6 +47,10 @@ const config = {
|
||||||
docs: {
|
docs: {
|
||||||
routeBasePath: '/',
|
routeBasePath: '/',
|
||||||
sidebarPath: './sidebars.js',
|
sidebarPath: './sidebars.js',
|
||||||
|
async sidebarItemsGenerator({ defaultSidebarItemsGenerator, ...args }) {
|
||||||
|
const sidebarItems = await defaultSidebarItemsGenerator(args)
|
||||||
|
return customizeSidebar(sidebarItems)
|
||||||
|
},
|
||||||
remarkPlugins: [[smartypants, { dashes: 'oldschool' }]],
|
remarkPlugins: [[smartypants, { dashes: 'oldschool' }]],
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
|
|
|
@ -389,7 +389,7 @@ export function measurementAsMm(value, units = 'metric') {
|
||||||
|
|
||||||
/** convert a millimeter value to a Number value in the given units */
|
/** convert a millimeter value to a Number value in the given units */
|
||||||
export function measurementAsUnits(mmValue, units = 'metric') {
|
export function measurementAsUnits(mmValue, units = 'metric') {
|
||||||
return round(mmValue / (units === 'imperial' ? 25.4 : 10), 3)
|
return round(mmValue / (units === 'imperial' ? 25.4 : 10), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -35,7 +35,7 @@ ApikeysController.prototype.list = async (req, res, tools) => {
|
||||||
/*
|
/*
|
||||||
* Read API key
|
* Read API key
|
||||||
*
|
*
|
||||||
* This is the endpoint that handles creation of API keys/tokens
|
* This is the endpoint that handles reading of API keys/tokens
|
||||||
* See: https://freesewing.dev/reference/backend/api/apikey
|
* See: https://freesewing.dev/reference/backend/api/apikey
|
||||||
*/
|
*/
|
||||||
ApikeysController.prototype.read = async (req, res, tools) => {
|
ApikeysController.prototype.read = async (req, res, tools) => {
|
||||||
|
|
|
@ -133,7 +133,7 @@ For example, if you want to put "_Finish with bias tape_" on your pattern, don't
|
||||||
tempted to do this:
|
tempted to do this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
path.seam.attr("data-text", "Finish with bias tape");
|
path.seam.attr('data-text', 'Finish with bias tape')
|
||||||
```
|
```
|
||||||
|
|
||||||
That (English) string is now hard-coded in your pattern. As FreeSewing supports
|
That (English) string is now hard-coded in your pattern. As FreeSewing supports
|
||||||
|
@ -142,16 +142,16 @@ translation out of the box, it would be a real shame not to make use of it.
|
||||||
Instead, insert a key to identify the string:
|
Instead, insert a key to identify the string:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
path.seam.attr("data-text", "finishWithBiasTape");
|
path.seam.attr('data-text', 'finishWithBiasTape')
|
||||||
```
|
```
|
||||||
|
|
||||||
This way, different strings for different languages can be associated with
|
This way, different strings for different languages can be associated with
|
||||||
the key, allowing translated text to be used.
|
the key, allowing translated text to be used.
|
||||||
|
|
||||||
You can find and browse the translations and available translation keys for each design in the design's
|
You can find and browse the translations and available translation keys for each design in the design's
|
||||||
[i18n folder on GitHub][1].
|
[i18n folder on Codeberg][1].
|
||||||
|
|
||||||
[1]: https://github.com/freesewing/freesewing/tree/develop/designs/aaron/i18n
|
[1]: https://codeberg.org/freesewing/freesewing/src/branch/develop/designs/aaron/i18n
|
||||||
|
|
||||||
## Construct paths counter-clockwise
|
## Construct paths counter-clockwise
|
||||||
|
|
||||||
|
@ -189,5 +189,3 @@ Constructing a path counter-clockwise will also ensure that the path offset goes
|
||||||
rather than inwards.
|
rather than inwards.
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,14 +31,12 @@ This method is chainable as it returns the `Part` object
|
||||||
<Example caption=" Example of the Part.attr() method">
|
<Example caption=" Example of the Part.attr() method">
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
;({ part, points, Point, Path, paths }) => {
|
||||||
|
points.A = new Point(0, 0)
|
||||||
|
points.B = new Point(0, 40)
|
||||||
|
points.C = new Point(100, 40)
|
||||||
|
|
||||||
({ part, points, Point, Path, paths }) => {
|
paths.line = new Path()
|
||||||
|
|
||||||
points.A = new Point(0,0)
|
|
||||||
points.B = new Point(0,40)
|
|
||||||
points.C = new Point(100,40)
|
|
||||||
|
|
||||||
paths.line = new Path()
|
|
||||||
.move(points.B)
|
.move(points.B)
|
||||||
.line(points.C)
|
.line(points.C)
|
||||||
.line(points.A)
|
.line(points.A)
|
||||||
|
@ -46,12 +44,12 @@ paths.line = new Path()
|
||||||
.close()
|
.close()
|
||||||
.addText('I have been flipped!', 'left')
|
.addText('I have been flipped!', 'left')
|
||||||
|
|
||||||
part.attr('transform', 'scale(1,-1) translate(0,-40)')
|
paths.bbox = new Path().move(new Point(0, -40)).move(new Point(120, 60))
|
||||||
|
|
||||||
return part
|
part.attr('transform', 'scale(1,-1) translate(0,-40)')
|
||||||
|
|
||||||
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</Example>
|
</Example>
|
||||||
|
|
||||||
|
|
|
@ -14,24 +14,25 @@ The draft method receives a single parameter, an object which you can _destructu
|
||||||
access the following properties:
|
access the following properties:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| --------:|:----------- |
|
| ----------------: | :------------------------------------------------------------------------------------------------------------ |
|
||||||
|| **_Content constructors_** |
|
| | **_Content constructors_** |
|
||||||
| `Path` | A [Path constructor](/reference/api/path) to create new paths |
|
| `Path` | A [Path constructor](/reference/api/path) to create new paths |
|
||||||
| `Point` | A [Point constructor](/reference/api/point) to create new points |
|
| `Point` | A [Point constructor](/reference/api/point) to create new points |
|
||||||
| `Snippet` | A [Snippet constructor](/reference/api/snippet) to create new snippets |
|
| `Snippet` | A [Snippet constructor](/reference/api/snippet) to create new snippets |
|
||||||
|| **_Content containers_** |
|
| | **_Content containers_** |
|
||||||
| `paths` | Add a Path to your part by adding it to this object |
|
| `paths` | Add a Path to your part by adding it to this object |
|
||||||
| `points` | Add a Points to your part by adding it to this object |
|
| `points` | Add a Points to your part by adding it to this object |
|
||||||
| `snippets` | Add a Snippet to your part by adding it to this object |
|
| `snippets` | Add a Snippet to your part by adding it to this object |
|
||||||
|| **_Access to settings_** |
|
| | **_Access to settings_** |
|
||||||
| `absoluteOptions` | Access to `settings.absoluteOptions` |
|
| `absoluteOptions` | Access to `settings.absoluteOptions` |
|
||||||
| `complete` | Access to `settings.complete` |
|
| `complete` | Access to `settings.complete` |
|
||||||
|
| `expand` | Access to `settings.expand` |
|
||||||
| `measurements` | Access to `settings.measurements` |
|
| `measurements` | Access to `settings.measurements` |
|
||||||
| `options` | Access to `settings.options` |
|
| `options` | Access to `settings.options` |
|
||||||
| `paperless` | Access to `settings.paperless` |
|
| `paperless` | Access to `settings.paperless` |
|
||||||
| `sa` | Access to `settings.sa` |
|
| `sa` | Access to `settings.sa` |
|
||||||
| `scale` | Access to `settings.scale` |
|
| `scale` | Access to `settings.scale` |
|
||||||
|| **_Access to utilities_** |
|
| | **_Access to utilities_** |
|
||||||
| `context` | Allows access to the pattern object and other things higher in the tree |
|
| `context` | Allows access to the pattern object and other things higher in the tree |
|
||||||
| `getId` | See [the getId documentation](/reference/api/part/getid) |
|
| `getId` | See [the getId documentation](/reference/api/part/getid) |
|
||||||
| `log` | See [the Store Methods documentation](/reference/store-methods#store-methods-we-maintain) |
|
| `log` | See [the Store Methods documentation](/reference/store-methods#store-methods-we-maintain) |
|
||||||
|
@ -40,7 +41,7 @@ access the following properties:
|
||||||
| `units` | A version of [`utils.units()`](/reference/api/utils/units) that is preconfigured with the user's chosen units |
|
| `units` | A version of [`utils.units()`](/reference/api/utils/units) that is preconfigured with the user's chosen units |
|
||||||
| `utils` | See [the utils documentation](/reference/api/utils) |
|
| `utils` | See [the utils documentation](/reference/api/utils) |
|
||||||
| `Bezier` | The [bezier-js](https://pomax.github.io/bezierjs/) library's `Bezier` named export |
|
| `Bezier` | The [bezier-js](https://pomax.github.io/bezierjs/) library's `Bezier` named export |
|
||||||
|| **_Return value_** |
|
| | **_Return value_** |
|
||||||
| `part` | Your draft method **must** return this |
|
| `part` | Your draft method **must** return this |
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
|
|
|
@ -40,15 +40,17 @@ snippets.point = new Snippet("notch", points.testPoint)
|
||||||
let angle = paths.demo.angleAt(points.testPoint)
|
let angle = paths.demo.angleAt(points.testPoint)
|
||||||
//draw a tangent path
|
//draw a tangent path
|
||||||
paths.tangent = new Path()
|
paths.tangent = new Path()
|
||||||
.move(points.testPoint.shift(angle, -30))
|
.move(points.testPoint.shift(angle, -30))
|
||||||
.line(points.testPoint.shift(angle, 30))
|
.line(points.testPoint.shift(angle, 30))
|
||||||
.attr("class", "lining dashed")
|
.attr("class", "lining dashed")
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
Keep in mind that calculations with Bézier curves are often approximations.
|
Keep in mind that calculations with Bézier curves are often approximations.
|
||||||
|
```
|
||||||
|
|
|
@ -12,33 +12,37 @@ Number path.roughLength()
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
<Example caption="Example of the Path.attr() method">
|
<Example caption="Example of the Path.roughLength() method">
|
||||||
```js
|
```js
|
||||||
({ Point, points, Path, paths, macro, units, part }) => {
|
({ Point, points, Path, paths, macro, units, part }) => {
|
||||||
|
|
||||||
points.B = new Point(10, 30)
|
points.B = new Point(10, 30)
|
||||||
points.BCp2 = new Point(40, 20)
|
points.BCp2 = new Point(40, 20)
|
||||||
points.C = new Point(120, 30)
|
points.C = new Point(120, 30)
|
||||||
points.CCp1 = new Point(50, -30)
|
points.CCp1 = new Point(50, -30)
|
||||||
|
|
||||||
paths.example = new Path()
|
paths.example = new Path()
|
||||||
.move(points.B)
|
.move(points.B)
|
||||||
.curve(points.BCp2, points.CCp1, points.C)
|
.curve(points.BCp2, points.CCp1, points.C)
|
||||||
|
|
||||||
macro("pd", {
|
macro("pd", {
|
||||||
path: paths.example,
|
path: paths.example,
|
||||||
d: -10,
|
id: 'macro1',
|
||||||
text: `Path.roughLength() = ${units(paths.example.roughLength())}`
|
d: -10,
|
||||||
})
|
force: true,
|
||||||
macro("pd", {
|
text: `Path.roughLength() = ${units(paths.example.roughLength())}`
|
||||||
path: paths.example,
|
})
|
||||||
d: 10,
|
macro("pd", {
|
||||||
text: `Path.length() = ${units(paths.example.length())}`
|
path: paths.example,
|
||||||
})
|
id: 'macro2',
|
||||||
|
d: 10,
|
||||||
|
force: true,
|
||||||
|
text: `Path.length() = ${units(paths.example.length())}`
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
return part
|
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
|
||||||
|
@ -48,3 +52,4 @@ The `Path.roughLength()` is not intended to give an estimate that is accurate, b
|
||||||
|
|
||||||
It calculates the length without *walking the (cubic) Bézier curve* making it very fast and very inaccurate (for curves).
|
It calculates the length without *walking the (cubic) Bézier curve* making it very fast and very inaccurate (for curves).
|
||||||
It is typically used to determine how much precision to apply when walking a curve.
|
It is typically used to determine how much precision to apply when walking a curve.
|
||||||
|
```
|
||||||
|
|
|
@ -14,7 +14,7 @@ Path path.smurve_(Point cp2, Point end)
|
||||||
```
|
```
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
This method is chainable as it returns the `Path` object
|
This method is chainable as it returns the `Path` objecti
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
|
@ -18,33 +18,39 @@ Path path.translate(float deltaX, float deltaY)
|
||||||
```js
|
```js
|
||||||
({ Point, points, Path, paths, part, macro }) => {
|
({ Point, points, Path, paths, part, macro }) => {
|
||||||
|
|
||||||
points.A = new Point(45, 60)
|
points.A = new Point(45, 60)
|
||||||
points.B = new Point(10, 30)
|
points.B = new Point(10, 30)
|
||||||
points.BCp2 = new Point(40, 20)
|
points.BCp2 = new Point(40, 20)
|
||||||
points.C = new Point(90, 30)
|
points.C = new Point(90, 30)
|
||||||
points.CCp1 = new Point(50, -30)
|
points.CCp1 = new Point(50, -30)
|
||||||
|
|
||||||
paths.A = new Path()
|
paths.A = new Path()
|
||||||
.move(points.A)
|
.move(points.A)
|
||||||
.line(points.B)
|
.line(points.B)
|
||||||
.curve(points.BCp2, points.CCp1, points.C)
|
.curve(points.BCp2, points.CCp1, points.C)
|
||||||
|
|
||||||
paths.B = paths.A.translate(60, 30)
|
paths.B = paths.A.translate(60, 30)
|
||||||
|
|
||||||
points.step1 = points.B.shift(0, 60)
|
points.step1 = points.B.shift(0, 60)
|
||||||
points.step2 = points.step1.shift(-90, 30)
|
points.step2 = points.step1.shift(-90, 30)
|
||||||
macro("ld", {
|
macro("ld", {
|
||||||
from: points.B,
|
from: points.B,
|
||||||
to: points.step1,
|
to: points.step1,
|
||||||
noStartMarker: true
|
noStartMarker: true,
|
||||||
})
|
id: 'macro1',
|
||||||
macro("ld", {
|
force: true,
|
||||||
from: points.step1,
|
})
|
||||||
to: points.step2,
|
macro("ld", {
|
||||||
noStartMarker: true
|
from: points.step1,
|
||||||
})
|
to: points.step2,
|
||||||
|
noStartMarker: true,
|
||||||
|
id: 'macro2',
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
```
|
||||||
|
|
|
@ -18,55 +18,77 @@ Point point.flipY(Point mirror = false)
|
||||||
```js
|
```js
|
||||||
({ Point, points, Path, paths, part }) => {
|
({ Point, points, Path, paths, part }) => {
|
||||||
|
|
||||||
points.start = new Point(0, 50)
|
points.start = new Point(0, 50)
|
||||||
points.churchTowerWallLeft = new Point(10, 50)
|
points.churchTowerWallLeft = new Point(10, 50)
|
||||||
points.churchTowerRoofLeft = new Point(10, 30)
|
points.churchTowerRoofLeft = new Point(10, 30)
|
||||||
points.churchTowerTop = new Point(15, 10)
|
points.churchTowerTop = new Point(15, 10)
|
||||||
points.churchTowerRoofRight = new Point(20, 30)
|
points.churchTowerRoofRight = new Point(20, 30)
|
||||||
points.churchRoofRight = new Point(50, 30)
|
points.churchRoofRight = new Point(50, 30)
|
||||||
points.churchWallRight = new Point(50, 50)
|
points.churchWallRight = new Point(50, 50)
|
||||||
points.houseWallLeft = new Point(65, 50)
|
points.houseWallLeft = new Point(65, 50)
|
||||||
points.houseRoofLeft = new Point(65, 35)
|
points.houseRoofLeft = new Point(65, 35)
|
||||||
points.houseRoofTop = new Point(75, 25)
|
points.houseRoofTop = new Point(75, 25)
|
||||||
points.houseRoofRight = new Point(85, 35)
|
points.houseRoofRight = new Point(85, 35)
|
||||||
points.houseWallRight = new Point(85, 50)
|
points.houseWallRight = new Point(85, 50)
|
||||||
points.end = new Point(95, 50)
|
points.end = new Point(95, 50)
|
||||||
|
|
||||||
points.mirror = new Point(0, 60)
|
points.mirror = new Point(0, 60)
|
||||||
points.mirrorLineEnd = new Point(95, 60)
|
points.mirrorLineEnd = new Point(95, 60)
|
||||||
|
|
||||||
points._start = points.start.flipY(points.mirror)
|
points.\_start = points.start.flipY(points.mirror)
|
||||||
points._churchTowerWallLeft = points.churchTowerWallLeft.flipY(points.mirror)
|
points.\_churchTowerWallLeft = points.churchTowerWallLeft.flipY(points.mirror)
|
||||||
points._churchTowerRoofLeft = points.churchTowerRoofLeft.flipY(points.mirror)
|
points.\_churchTowerRoofLeft = points.churchTowerRoofLeft.flipY(points.mirror)
|
||||||
points._churchTowerTop = points.churchTowerTop.flipY(points.mirror)
|
points.\_churchTowerTop = points.churchTowerTop.flipY(points.mirror)
|
||||||
points._churchTowerRoofRight = points.churchTowerRoofRight.flipY(
|
points.\_churchTowerRoofRight = points.churchTowerRoofRight.flipY(
|
||||||
points.mirror
|
points.mirror
|
||||||
)
|
)
|
||||||
points._churchRoofRight = points.churchRoofRight.flipY(points.mirror)
|
points.\_churchRoofRight = points.churchRoofRight.flipY(points.mirror)
|
||||||
points._churchWallRight = points.churchWallRight.flipY(points.mirror)
|
points.\_churchWallRight = points.churchWallRight.flipY(points.mirror)
|
||||||
points._houseWallLeft = points.houseWallLeft.flipY(points.mirror)
|
points.\_houseWallLeft = points.houseWallLeft.flipY(points.mirror)
|
||||||
points._houseRoofLeft = points.houseRoofLeft.flipY(points.mirror)
|
points.\_houseRoofLeft = points.houseRoofLeft.flipY(points.mirror)
|
||||||
points._houseRoofTop = points.houseRoofTop.flipY(points.mirror)
|
points.\_houseRoofTop = points.houseRoofTop.flipY(points.mirror)
|
||||||
points._houseRoofRight = points.houseRoofRight.flipY(points.mirror)
|
points.\_houseRoofRight = points.houseRoofRight.flipY(points.mirror)
|
||||||
points._houseWallRight = points.houseWallRight.flipY(points.mirror)
|
points.\_houseWallRight = points.houseWallRight.flipY(points.mirror)
|
||||||
points._end = points.end.flipY(points.mirror)
|
points.\_end = points.end.flipY(points.mirror)
|
||||||
|
|
||||||
paths.skylineTop = new Path()
|
paths.skylineTop = new Path()
|
||||||
.move(points.start)
|
.move(points.start)
|
||||||
.line(points.churchTowerWallLeft)
|
.line(points.churchTowerWallLeft)
|
||||||
.line(points.churchTowerRoofLeft)
|
.line(points.churchTowerRoofLeft)
|
||||||
.line(points.churchTowerTop)
|
.line(points.churchTowerTop)
|
||||||
.line(points.churchTowerRoofRight)
|
.line(points.churchTowerRoofRight)
|
||||||
.line(points.churchRoofRight)
|
.line(points.churchRoofRight)
|
||||||
.line(points.churchWallRight)
|
.line(points.churchWallRight)
|
||||||
.line(points.houseWallLeft)
|
.line(points.houseWallLeft)
|
||||||
.line(points.houseRoofLeft)
|
.line(points.houseRoofLeft)
|
||||||
.line(points.houseRoofTop)
|
.line(points.houseRoofTop)
|
||||||
.line(points.houseRoofRight)
|
.line(points.houseRoofRight)
|
||||||
.line(points.houseWallRight)
|
.line(points.houseWallRight)
|
||||||
.line(points.end)
|
.line(points.end)
|
||||||
|
|
||||||
return part
|
paths.skylineBot = new Path()
|
||||||
|
.move(points.\_start)
|
||||||
|
.line(points.\_churchTowerWallLeft)
|
||||||
|
.line(points.\_churchTowerRoofLeft)
|
||||||
|
.line(points.\_churchTowerTop)
|
||||||
|
.line(points.\_churchTowerRoofRight)
|
||||||
|
.line(points.\_churchRoofRight)
|
||||||
|
.line(points.\_churchWallRight)
|
||||||
|
.line(points.\_houseWallLeft)
|
||||||
|
.line(points.\_houseRoofLeft)
|
||||||
|
.line(points.\_houseRoofTop)
|
||||||
|
.line(points.\_houseRoofRight)
|
||||||
|
.line(points.\_houseWallRight)
|
||||||
|
.line(points.\_end)
|
||||||
|
|
||||||
|
paths.mirror = new Path()
|
||||||
|
.move(points.mirror)
|
||||||
|
.line(points.mirrorLineEnd)
|
||||||
|
.setClass("note dashed")
|
||||||
|
|
||||||
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
```
|
||||||
|
|
|
@ -18,19 +18,23 @@ Point point.shift(float angle, float distance)
|
||||||
```js
|
```js
|
||||||
({ Point, points, macro, part }) => {
|
({ Point, points, macro, part }) => {
|
||||||
|
|
||||||
points.A = new Point(90, 40)
|
points.A = new Point(90, 40)
|
||||||
.setText("Point A", "right text-sm")
|
.setText("Point A", "right text-sm")
|
||||||
points.B = points.A.shift(155, 70)
|
points.B = points.A.shift(155, 70)
|
||||||
.setText("Point B is point A shifted 7 cm\nat a 155 degree angle", "text-sm")
|
.setText("Point B is point A shifted 7 cm\nat a 155 degree angle", "text-sm")
|
||||||
.attr("data-text-lineheight", 6)
|
.attr("data-text-lineheight", 6)
|
||||||
|
|
||||||
macro("ld", {
|
macro("ld", {
|
||||||
from: points.B,
|
from: points.B,
|
||||||
to: points.A,
|
to: points.A,
|
||||||
d: -10
|
d: -10,
|
||||||
})
|
id: 'macro1',
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
```
|
||||||
|
|
|
@ -15,40 +15,45 @@ negative values to shift the point in the opposite direction.
|
||||||
Point point.shiftFractionTowards(Point target, float fraction)
|
Point point.shiftFractionTowards(Point target, float fraction)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Point.shiftFractionTowards() example
|
## Example
|
||||||
|
|
||||||
<Example caption="An example of the Point.shiftFractionTowards() method">
|
<Example caption="An example of the Point.shiftFractionTowards() method">
|
||||||
```js
|
```js
|
||||||
({ Point, points, Path, paths, macro, part }) => {
|
({ Point, points, Path, paths, macro, part }) => {
|
||||||
|
|
||||||
points.A = new Point(90, 70).setText("Point A", "text-sm")
|
points.A = new Point(90, 70).setText("Point A", "text-sm")
|
||||||
points.B = new Point(10, 10).setText("Point B", "text-sm")
|
points.B = new Point(10, 10).setText("Point B", "text-sm")
|
||||||
points.C = points.A.shiftFractionTowards(points.B, 0.5)
|
points.C = points.A.shiftFractionTowards(points.B, 0.5)
|
||||||
.setText(
|
.setText(
|
||||||
"Point C is point A shifted 50%\nin the direction of point B",
|
"Point C is point A shifted 50%\nin the direction of point B",
|
||||||
"center text-sm"
|
"center text-sm"
|
||||||
)
|
)
|
||||||
.attr("data-text-lineheight", 6)
|
.attr("data-text-lineheight", 6)
|
||||||
|
|
||||||
paths.direction = new Path()
|
paths.direction = new Path()
|
||||||
.move(points.A)
|
.move(points.A)
|
||||||
.line(points.B)
|
.line(points.B)
|
||||||
.setClass("note dashed")
|
.setClass("note dashed")
|
||||||
|
|
||||||
macro("ld", {
|
macro("ld", {
|
||||||
from: points.C,
|
from: points.C,
|
||||||
to: points.A,
|
to: points.A,
|
||||||
d: -10
|
d: -10,
|
||||||
})
|
id: 'macro1',
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
|
||||||
macro("ld", {
|
macro("ld", {
|
||||||
from: points.B,
|
from: points.B,
|
||||||
to: points.A,
|
to: points.A,
|
||||||
d: 20
|
d: 20,
|
||||||
})
|
id: 'macro2',
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
|
||||||
|
@ -58,3 +63,4 @@ Point point.shiftFractionTowards(Point target, float fraction)
|
||||||
If you need to move a point by a specific distance instead of a percentage, use
|
If you need to move a point by a specific distance instead of a percentage, use
|
||||||
[`Point.shiftTowards()`](/reference/api/point/shifttowards/) or
|
[`Point.shiftTowards()`](/reference/api/point/shifttowards/) or
|
||||||
[`Point.shiftOutwards()`](/reference/api/point/shiftoutwards/) instead.
|
[`Point.shiftOutwards()`](/reference/api/point/shiftoutwards/) instead.
|
||||||
|
```
|
||||||
|
|
|
@ -17,24 +17,27 @@ Point point.shiftOutwards(Point target, float distance)
|
||||||
```js
|
```js
|
||||||
({ Point, points, Path, paths, macro, part }) => {
|
({ Point, points, Path, paths, macro, part }) => {
|
||||||
|
|
||||||
points.A = new Point(90, 70).setText("Point A", "text-sm right")
|
points.A = new Point(90, 70).setText("Point A", "text-sm right")
|
||||||
points.B = new Point(10, 10).setText("Point B", "text-sm")
|
points.B = new Point(10, 10).setText("Point B", "text-sm")
|
||||||
points.C = points.A.shiftOutwards(points.B, 30)
|
points.C = points.A.shiftOutwards(points.B, 30)
|
||||||
.setText("Point C is point A shifted 3 cm\nbeyond point B", "text-sm")
|
.setText("Point C is point A shifted 3 cm\nbeyond point B", "text-sm")
|
||||||
.attr("data-text-lineheight", 6)
|
.attr("data-text-lineheight", 6)
|
||||||
|
|
||||||
paths.direction = new Path()
|
paths.direction = new Path()
|
||||||
.move(points.A)
|
.move(points.A)
|
||||||
.line(points.C)
|
.line(points.C)
|
||||||
.addClass("note dashed")
|
.addClass("note dashed")
|
||||||
|
|
||||||
macro("ld", {
|
macro("ld", {
|
||||||
from: points.C,
|
from: points.C,
|
||||||
to: points.B,
|
to: points.B,
|
||||||
d: -10
|
d: -10,
|
||||||
})
|
force: true,
|
||||||
|
})
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
```
|
||||||
|
|
|
@ -17,25 +17,32 @@ Point point.shiftTowards(Point target, float distance)
|
||||||
```js
|
```js
|
||||||
({ Point, points, Path, paths, macro, part }) => {
|
({ Point, points, Path, paths, macro, part }) => {
|
||||||
|
|
||||||
points.A = new Point(90, 70).setText("Point A", "right text-sm")
|
points.A = new Point(90, 70).setText("Point A", "right text-sm")
|
||||||
points.B = new Point(10, 10).setText("Point B", "text-sm")
|
points.B = new Point(10, 10).setText("Point B", "text-sm")
|
||||||
points.C = points.A.shiftTowards(points.B, 35)
|
points.C = points.A.shiftTowards(points.B, 35)
|
||||||
.setText("Point C is point A shifted 3.5 cm\nin the direction of point B", "center, text-sm")
|
.setText("Point C is point A shifted 3.5 cm\nin the direction of point B", "center, text-sm")
|
||||||
.attr("data-text-lineheight", 6)
|
.attr("data-text-lineheight", 6)
|
||||||
|
|
||||||
paths.direction = new Path()
|
paths.direction = new Path()
|
||||||
.move(points.A)
|
.move(points.A)
|
||||||
.line(points.B)
|
.line(points.B)
|
||||||
.addClass("note dashed")
|
.addClass("note dashed")
|
||||||
|
|
||||||
macro("ld", {
|
macro("ld", {
|
||||||
from: points.C,
|
from: points.C,
|
||||||
to: points.A,
|
to: points.A,
|
||||||
d: -10
|
d: -10,
|
||||||
})
|
force: true,
|
||||||
|
})
|
||||||
|
|
||||||
return part
|
// Boundary box
|
||||||
|
paths.bbox = new Path()
|
||||||
|
.move(new Point(10,10))
|
||||||
|
.move(new Point(125,70))
|
||||||
|
|
||||||
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
|
||||||
|
@ -45,3 +52,4 @@ Point point.shiftTowards(Point target, float distance)
|
||||||
If you need to move a point a percentage instead of a specific distance, use
|
If you need to move a point a percentage instead of a specific distance, use
|
||||||
[`Point.shiftFractionTowards()`](/reference/api/point/shiftfractiontowards/)
|
[`Point.shiftFractionTowards()`](/reference/api/point/shiftfractiontowards/)
|
||||||
instead.
|
instead.
|
||||||
|
```
|
||||||
|
|
|
@ -7,9 +7,7 @@ The `Point.slope()` method returns the slope (dy/dx) of a line between two Point
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
||||||
point.slope(otherPoint)
|
point.slope(otherPoint)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
@ -17,11 +15,9 @@ point.slope(otherPoint)
|
||||||
<Example caption="An example of the Point.slope() method">
|
<Example caption="An example of the Point.slope() method">
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
;({ Point, points, Path, paths, Snippet, snippets, part, macro }) => {
|
||||||
({ Point, points, Path, paths, Snippet, snippets, part, macro }) => {
|
points.A = new Point(0, 0)
|
||||||
|
points.B = new Point(200, 150)
|
||||||
points.A = new Point(0,0)
|
|
||||||
points.B = new Point(200,150)
|
|
||||||
|
|
||||||
const slope = points.A.slope(points.B)
|
const slope = points.A.slope(points.B)
|
||||||
|
|
||||||
|
@ -29,21 +25,25 @@ point.slope(otherPoint)
|
||||||
from: points.A,
|
from: points.A,
|
||||||
to: points.B,
|
to: points.B,
|
||||||
y: points.B.y,
|
y: points.B.y,
|
||||||
|
id: 'macro1',
|
||||||
|
force: true,
|
||||||
})
|
})
|
||||||
macro('vd', {
|
macro('vd', {
|
||||||
to: points.B,
|
to: points.B,
|
||||||
from: points.A,
|
from: points.A,
|
||||||
x: 0,
|
x: 0,
|
||||||
|
id: 'macro2',
|
||||||
|
force: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
paths.line = new Path()
|
paths.line = new Path()
|
||||||
.move(points.A)
|
.move(points.A)
|
||||||
.line(points.B)
|
.line(points.B)
|
||||||
.attr("class", "canvas")
|
.attr('class', 'canvas')
|
||||||
.setText("Slope: " + slope, "center text-lg")
|
.setText('Slope: ' + slope, 'center text-lg')
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</Example>
|
</Example>
|
||||||
|
|
|
@ -24,28 +24,36 @@ Positive values for `deltaY` will move the point downwards.
|
||||||
|
|
||||||
<Example caption="An example of the Point.translate() method">
|
<Example caption="An example of the Point.translate() method">
|
||||||
```js
|
```js
|
||||||
({ Point, points, Snippet, snippets, macro, part }) => {
|
({ Point, points, Path, paths, Snippet, snippets, macro, part }) => {
|
||||||
|
|
||||||
points.A = new Point(10, 10).setText("Point A", "text-sm")
|
points.A = new Point(10, 10).setText("Point A", "text-sm")
|
||||||
points.B = points.A.translate(120, 60)
|
points.B = points.A.translate(120, 60)
|
||||||
.setText(
|
.setText(
|
||||||
"Point B is point A with a\ntranslate(120, 60)\ntransform applied",
|
"Point B is point A with a\ntranslate(120, 60)\ntransform applied",
|
||||||
"right text-sm"
|
"right text-sm"
|
||||||
)
|
)
|
||||||
.attr("data-text-dy", -6)
|
.attr("data-text-dy", -6)
|
||||||
.attr("data-text-lineheight", 6)
|
.attr("data-text-lineheight", 6)
|
||||||
|
|
||||||
snippets.A = new Snippet("x", points.A)
|
snippets.A = new Snippet("x", points.A)
|
||||||
snippets.B = new Snippet("x", points.B)
|
snippets.B = new Snippet("x", points.B)
|
||||||
|
|
||||||
macro("ld", {
|
macro("ld", {
|
||||||
from: points.A,
|
from: points.A,
|
||||||
to: points.B,
|
to: points.B,
|
||||||
text: "translate(120,60)",
|
text: "translate(120,60)",
|
||||||
noStartMarker: true
|
noStartMarker: true,
|
||||||
})
|
force: true,
|
||||||
|
})
|
||||||
|
|
||||||
return part
|
// Bounding box
|
||||||
|
paths.bbox = new Path()
|
||||||
|
.move(new Point(10, 10))
|
||||||
|
.move(new Point(130, 80))
|
||||||
|
|
||||||
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
</Example>
|
</Example>
|
||||||
|
```
|
||||||
|
|
|
@ -17,7 +17,7 @@ This method is chainable as it returns the `Snippet` object
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
<Example caption="An example of the Snippet.clone() method">
|
<Example caption="An example of the Snippet.scale() method">
|
||||||
```js
|
```js
|
||||||
({ Point, Path, paths, Snippet, snippets, part }) => {
|
({ Point, Path, paths, Snippet, snippets, part }) => {
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,22 @@ SVG document.
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```svg
|
```js
|
||||||
|
Defs svg.defs = {
|
||||||
|
list = {
|
||||||
|
buttonhole: `<g id="buttonhole" transform="scale(1)">
|
||||||
|
<path class="mark" d="M -1,-5 L 1,-5 L 1,5 L -1,5 z"></path>
|
||||||
|
</g>`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
|
```
|
||||||
<defs>
|
<defs>
|
||||||
/* svg.defs will be inserted */
|
<g id="buttonhole" transform="scale(1)">
|
||||||
|
<path class="mark" d="M -1,-5 L 1,-5 L 1,5 L -1,5 z"></path>
|
||||||
|
</g>
|
||||||
</defs>
|
</defs>
|
||||||
```
|
```
|
||||||
|
|
|
@ -7,9 +7,17 @@ section of the SVG document.
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```svg
|
```js
|
||||||
|
String svg.style += 'circle {stroke:black;}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
|
```
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
/* svg.style will be inserted */
|
circle {
|
||||||
|
stroke: black;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,15 @@ title: hem
|
||||||
|
|
||||||
The `hem` macro drafts a hem allowance with fold lines.
|
The `hem` macro drafts a hem allowance with fold lines.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
|
||||||
|
##### Not a core-plugins macro
|
||||||
|
|
||||||
|
The `hem` macro is not provided by the [core plugins](/reference/plugins/core),
|
||||||
|
so you need to load the [path-utils plugin](/reference/plugins/path-utils)
|
||||||
|
explicitly if you want to use it.
|
||||||
|
:::
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -68,7 +77,7 @@ Path macro('hem', {
|
||||||
| `prefix` | `'hemMacro'` | `number` | The name prefix used for paths created by this macro. |
|
| `prefix` | `'hemMacro'` | `number` | The name prefix used for paths created by this macro. |
|
||||||
| `cssClass` | `'fabric'` | `number` | The CSS class added to the fold lines and the hem outline. Should usually match the CSS class for the part outline |
|
| `cssClass` | `'fabric'` | `number` | The CSS class added to the fold lines and the hem outline. Should usually match the CSS class for the part outline |
|
||||||
|
|
||||||
## Detailed Description
|
## Notes
|
||||||
|
|
||||||
This macro will create the following paths (assuming the default `'hemMacro'` prefix is used):
|
This macro will create the following paths (assuming the default `'hemMacro'` prefix is used):
|
||||||
|
|
||||||
|
|
|
@ -4,31 +4,20 @@ title: join
|
||||||
|
|
||||||
The `join` macro joins multiple paths together.
|
The `join` macro joins multiple paths together.
|
||||||
|
|
||||||
Unlike the core `path.join(...)` function, the `join` macro can extend line ends to meet in a sharp corner and will automatically
|
Unlike the core [`Path.join()`](/reference/api/path/join) function,
|
||||||
trim useless path ends when adjacent paths in the array are intersecting.
|
the `join` macro can extend line ends to meet in a sharp corner and
|
||||||
|
will automatically trim useless path ends when adjacent paths in the
|
||||||
|
array are intersecting.
|
||||||
|
|
||||||
The join function accepts an array of `Path` objects
|
:::note
|
||||||
(either names in the `paths` array or direct references to `Path` objects).
|
|
||||||
This array can contain `null` values or hidden paths (created with `path.hide()`) to create gaps.
|
|
||||||
|
|
||||||
:::warning
|
##### Not a core-plugins macro
|
||||||
|
|
||||||
Since hidden paths will create gaps in the resulting paths, make sure that all the paths you want to
|
|
||||||
include in the join are visible before calling the macro.
|
|
||||||
|
|
||||||
You can hide them afterwards again, if needed.
|
|
||||||
|
|
||||||
|
The `join` macro is not provided by the [core plugins](/reference/plugins/core),
|
||||||
|
so you need to load the [path-utils plugin](/reference/plugins/path-utils)
|
||||||
|
explicitly if you want to use it.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
By default, the `join` macro will join the paths in a circular fashion, joining the end
|
|
||||||
of the last path in the array to the start of the first path, creating a full outline.
|
|
||||||
If this is not desired, insert a `null` element between paths where you want the gap
|
|
||||||
(or at the end of the `paths` parameter).
|
|
||||||
|
|
||||||
Note that a `null` value will create a basic gap in the output,
|
|
||||||
if you instead include a hidden path, this method will still create sharp corners as if the path were present,
|
|
||||||
but the actual path will be skipped in the output.
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -72,5 +61,29 @@ Path macro('join', {
|
||||||
| Property | Default | Type | Description |
|
| Property | Default | Type | Description |
|
||||||
| -------: | ---------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| -------: | ---------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `paths` | | `array` | An array of pathnames, the names of Paths in the `paths` array to join (you can also reference `Path` objects directly, or insert `null` elements to create gaps) |
|
| `paths` | | `array` | An array of pathnames, the names of Paths in the `paths` array to join (you can also reference `Path` objects directly, or insert `null` elements to create gaps) |
|
||||||
| `mode` | `'corner'` | `string` | Mode for joining paths. Either `'corner'` or `'cut'`. `'cut'` will join the paths directly without extending them (like `path.join(...)`). |
|
| `mode` | `'corner'` | `string` | Mode for joining paths. Either `'corner'` or `'cut'`. `'cut'` will join the paths directly without extending them (like `Path.join()`). |
|
||||||
| `limit` | `null` | `number` | Allows limiting the length of corners in `'corner'` mode. Prevents overly long joins on very sharp angles. Ignored if `null` or `false`. |
|
| `limit` | `null` | `number` | Allows limiting the length of corners in `'corner'` mode. Prevents overly long joins on very sharp angles. Ignored if `null` or `false`. |
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
The `join` macro accepts an array of `Path` objects
|
||||||
|
(either names in the `paths` array or direct references to `Path` objects).
|
||||||
|
This array can contain `null` values or hidden paths (created with `Path.hide()`) to create gaps.
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
|
||||||
|
Since hidden paths will create gaps in the resulting paths, make sure that all the paths you want to
|
||||||
|
include in the join are visible before calling the macro.
|
||||||
|
|
||||||
|
You can hide them afterwards again, if needed.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
By default, the `join` macro will join the paths in a circular fashion, joining the end
|
||||||
|
of the last path in the array to the start of the first path, creating a full outline.
|
||||||
|
If this is not desired, insert a `null` element between paths where you want the gap
|
||||||
|
(or at the end of the `paths` parameter).
|
||||||
|
|
||||||
|
Note that a `null` value will create a basic gap in the output.
|
||||||
|
If you instead include a hidden path, this method will still create sharp corners as if the path were present,
|
||||||
|
but the actual path will be skipped in the output.
|
||||||
|
|
|
@ -4,25 +4,18 @@ title: offset
|
||||||
|
|
||||||
The `offset` macro will offset and join paths.
|
The `offset` macro will offset and join paths.
|
||||||
|
|
||||||
Unlike the core `path.join(...)` and `path.offset(...)` functions, the `offset` macro can extend line ends to meet in a sharp corner and will automatically
|
Unlike the core [`Path.join()`](/reference/api/path/join) and
|
||||||
|
[`Path.offset()`](/reference/api/path/offset) functions, the `offset`
|
||||||
|
macro can extend line ends to meet in a sharp corner and will automatically
|
||||||
trim useless path ends when adjacent paths in the array are intersecting.
|
trim useless path ends when adjacent paths in the array are intersecting.
|
||||||
|
|
||||||
The offset macro accepts an array of `Path` objects with their offset, like `{p: 'somePath', offset: 30}` or `{p: ['path1', 'path2'], offset: sa * 3, hidden: true}`.
|
|
||||||
For the paths in the `p` attribute, you can reference either names in the `paths` array or insert direct references to `Path` objects.
|
|
||||||
The array can contain `null` values to create gaps (e.g., for cuts on the fold or for other sections that don't need seam allowance).
|
|
||||||
|
|
||||||
By default, the `offset` macro will offset the paths in a circular fashion, joining the end
|
|
||||||
of the last path in the array to the start of the first path, creating a full outline.
|
|
||||||
If this is not desired, insert `null` elements where you want to create gaps.
|
|
||||||
|
|
||||||
You can use `offset: 0` to include paths which don't need an additional offset.
|
|
||||||
|
|
||||||
You can use `hidden: true` to omit path segments from the output, but still build corner joins as if they were there.
|
|
||||||
This can be used for cut-on-fold lines, where no seam allowance is needed.
|
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
To create a seam allowance, prefer the `sa` macro instead of the `offset` macro. It does pretty much the same,
|
|
||||||
but the `sa` macro defaults to offsetting paths by the user defined seam allowance.
|
##### Not a core-plugins macro
|
||||||
|
|
||||||
|
The `offset` macro is not provided by the [core plugins](/reference/plugins/core),
|
||||||
|
so you need to load the [path-utils plugin](/reference/plugins/path-utils)
|
||||||
|
explicitly if you want to use it.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
@ -79,6 +72,27 @@ Path macro('offset', {
|
||||||
| Property | Default | Type | Description |
|
| Property | Default | Type | Description |
|
||||||
| -------: | ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| -------: | ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `paths` | | `array` | An array of paths with their offset and visibility. You can use path names in the `paths` array or reference `Path` objects directly, or insert `null` elements to create gaps. |
|
| `paths` | | `array` | An array of paths with their offset and visibility. You can use path names in the `paths` array or reference `Path` objects directly, or insert `null` elements to create gaps. |
|
||||||
| `mode` | `'corner'` | `string` | Mode for joining paths. Either `'corner'` or `'cut'`. `'cut'` will join the paths directly (like `path.join(...)`) without extending the corners. |
|
| `mode` | `'corner'` | `string` | Mode for joining paths. Either `'corner'` or `'cut'`. `'cut'` will join the paths directly (like `Path.join()`) without extending the corners. |
|
||||||
| `limit` | `null` | `number` | Allows limiting the length of extended path corners in `'corner'` mode. Prevents overly long joins on very sharp angles. Ignored if `null` or `false`. |
|
| `limit` | `null` | `number` | Allows limiting the length of extended path corners in `'corner'` mode. Prevents overly long joins on very sharp angles. Ignored if `null` or `false`. |
|
||||||
| `class` | `'offset'` | `string` | CSS class that is automatically applied to the resulting path. |
|
| `class` | `'offset'` | `string` | CSS class that is automatically applied to the resulting path. |
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
The `offset` macro accepts an array of `Path` objects with their offset, like `{p: 'somePath', offset: 30}` or `{p: ['path1', 'path2'], offset: sa * 3, hidden: true}`.
|
||||||
|
For the paths in the `p` attribute, you can reference either names in the `paths` array or insert direct references to `Path` objects.
|
||||||
|
The array can contain `null` values to create gaps (e.g., for cuts on the fold or for other sections that don't need seam allowance).
|
||||||
|
|
||||||
|
By default, the `offset` macro will offset the paths in a circular fashion, joining the end
|
||||||
|
of the last path in the array to the start of the first path, creating a full outline.
|
||||||
|
If this is not desired, insert `null` elements where you want to create gaps.
|
||||||
|
|
||||||
|
You can use `offset: 0` to include paths which don't need an additional offset.
|
||||||
|
|
||||||
|
You can use `hidden: true` to omit path segments from the output, but still build corner joins as if they were there.
|
||||||
|
This can be used for cut-on-fold lines, where no seam allowance is needed.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
To create a seam allowance, prefer the [`sa`](/reference/macros/sa) macro
|
||||||
|
instead of the `offset` macro. It does pretty much the same,
|
||||||
|
but the `sa` macro defaults to offsetting paths by the user defined seam allowance.
|
||||||
|
:::
|
||||||
|
|
|
@ -4,24 +4,20 @@ title: sa
|
||||||
|
|
||||||
The `sa` macro will create seam allowance paths.
|
The `sa` macro will create seam allowance paths.
|
||||||
|
|
||||||
Unlike the core `path.join(...)` and `path.offset(...)` functions, the `sa` macro can extend line ends to meet in a sharp corner and will automatically
|
Unlike the core [`Path.join()`](/reference/api/path/join) and
|
||||||
trim useless path ends when adjacent paths in the array are intersecting.
|
[`Path.offset()`](/reference/api/path/offset) functions, the
|
||||||
|
`sa` macro can extend line ends to meet in a sharp corner and
|
||||||
|
will automatically trim useless path ends when adjacent paths
|
||||||
|
in the array are intersecting.
|
||||||
|
|
||||||
The sa macro accepts an array of `Path` objects
|
:::note
|
||||||
(either names in the `paths` array or direct references to `Path` objects).
|
|
||||||
This array can contain `null` values to create gaps (e.g. for cuts on the fold or for other sections that don't need seam allowance).
|
|
||||||
|
|
||||||
By default, the `sa` macro will sa the paths in a circular fashion, joining the end
|
##### Not a core-plugins macro
|
||||||
of the last path in the array to the start of the first path, creating a full outline.
|
|
||||||
If this is not desired, insert `null` elements where you want to create gaps.
|
|
||||||
|
|
||||||
You can optionally override the offset and invisibility for individual paths.
|
The `sa` macro is not provided by the [core plugins](/reference/plugins/core),
|
||||||
To do so, insert an object literal like `{p: 'somePath', offset: 30}` or `{p: ['path1', 'path2'], offset: sa * 3, hidden: true}` into the `paths` array.
|
so you need to load the [path-utils plugin](/reference/plugins/path-utils)
|
||||||
|
explicitly if you want to use it.
|
||||||
You can use `offset: 0` to include paths which have already build-in the seam allowance (e.g. the result of the `hem` macro).
|
:::
|
||||||
|
|
||||||
You can use `hidden: true` to hide path segments from the output, but still build corner joins as if they were there.
|
|
||||||
This can be used for cut-on-fold lines, where no seam allowance is needed.
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
|
@ -76,7 +72,25 @@ macro('sa', {
|
||||||
| Property | Default | Type | Description |
|
| Property | Default | Type | Description |
|
||||||
| -------: | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| -------: | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `paths` | | `array` | An array of paths. You can use path names in the `paths` array or reference `Path` objects directly, or insert `null` elements to create gaps. You can also override offset and visibility for individual paths in the same way as with the `offset` macro. |
|
| `paths` | | `array` | An array of paths. You can use path names in the `paths` array or reference `Path` objects directly, or insert `null` elements to create gaps. You can also override offset and visibility for individual paths in the same way as with the `offset` macro. |
|
||||||
| `mode` | `'corner'` | `string` | Mode for joining paths. Either `'corner'` or `'cut'`. `'cut'` will join the paths directly (like `path.join(...)`) without extending the corners. |
|
| `mode` | `'corner'` | `string` | Mode for joining paths. Either `'corner'` or `'cut'`. `'cut'` will join the paths directly (like `Path.join()`) without extending the corners. |
|
||||||
| `limit` | `null` | `number` | Allows limiting the length of extended path corners in `'corner'` mode. Prevents overly long joins on very sharp angles. Ignored if `null` or `false`. |
|
| `limit` | `null` | `number` | Allows limiting the length of extended path corners in `'corner'` mode. Prevents overly long joins on very sharp angles. Ignored if `null` or `false`. |
|
||||||
| `sa` | (seam allowance) | `number` | Allows you to override the seam allowance used for this macro. Defaults to the standard seam allowance (`sa` parameter in draft function). |
|
| `sa` | (seam allowance) | `number` | Allows you to override the seam allowance used for this macro. Defaults to the standard seam allowance (`sa` parameter in draft function). |
|
||||||
| `class` | `'sa'` | `string` | CSS class that is automatically applied to the resulting path. |
|
| `class` | `'sa'` | `string` | CSS class that is automatically applied to the resulting path. |
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
The `sa` macro accepts an array of `Path` objects
|
||||||
|
(either names in the `paths` array or direct references to `Path` objects).
|
||||||
|
This array can contain `null` values to create gaps (e.g. for cuts on the fold or for other sections that don't need seam allowance).
|
||||||
|
|
||||||
|
By default, the `sa` macro will sa the paths in a circular fashion, joining the end
|
||||||
|
of the last path in the array to the start of the first path, creating a full outline.
|
||||||
|
If this is not desired, insert `null` elements where you want to create gaps.
|
||||||
|
|
||||||
|
You can optionally override the offset and invisibility for individual paths.
|
||||||
|
To do so, insert an object literal like `{p: 'somePath', offset: 30}` or `{p: ['path1', 'path2'], offset: sa * 3, hidden: true}` into the `paths` array.
|
||||||
|
|
||||||
|
You can use `offset: 0` to include paths which have already build-in the seam allowance (e.g. the result of the `hem` macro).
|
||||||
|
|
||||||
|
You can use `hidden: true` to hide path segments from the output, but still build corner joins as if they were there.
|
||||||
|
This can be used for cut-on-fold lines, where no seam allowance is needed.
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
title: plugin-path-utils
|
title: plugin-path-utils
|
||||||
---
|
---
|
||||||
|
|
||||||
Published as [@freesewing/plugin-path-utils][1], this plugin provides the [hem](/reference/macros/hem), [sa](/reference/macros/sa), [offset](/reference/macros/offset) and [sa](/reference/macros/join) macros,
|
Published as [@freesewing/plugin-path-utils][1], this plugin provides the
|
||||||
|
[hem](/reference/macros/hem), [join](/reference/macros/join),
|
||||||
|
[offset](/reference/macros/offset), and [sa](/reference/macros/sa) macros,
|
||||||
whose main purpose is to make it easier to construct seam allowance paths.
|
whose main purpose is to make it easier to construct seam allowance paths.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
@ -25,10 +27,4 @@ import { pathUtilsPlugin } from '@freesewing/plugin-path-utils'
|
||||||
import { pluginPathUtils } from '@freesewing/plugin-path-utils'
|
import { pluginPathUtils } from '@freesewing/plugin-path-utils'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
This plugin is part of the [core-plugins bundle](/reference/plugins/core),
|
|
||||||
so there is no need to install or import it manually unless you wish to forego
|
|
||||||
loading of core plugins yet still want to load this plugin.
|
|
||||||
|
|
||||||
[1]: https://www.npmjs.com/package/@freesewing/plugin-path-utils
|
[1]: https://www.npmjs.com/package/@freesewing/plugin-path-utils
|
||||||
|
|
44
sites/dev/docs/reference/settings/expand/readme.mdx
Normal file
44
sites/dev/docs/reference/settings/expand/readme.mdx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
title: expand
|
||||||
|
---
|
||||||
|
|
||||||
|
The `expand` setting controls whether all parts should be fully
|
||||||
|
drawn in a pattern.
|
||||||
|
Set `expand` to `false` when the pattern should instead omit parts and/or
|
||||||
|
draw abbreviated parts.
|
||||||
|
|
||||||
|
Omitting parts and using abbreviated parts saves space and paper
|
||||||
|
in printed patterns.
|
||||||
|
Typically, this is done for parts that are simple shapes like
|
||||||
|
rectangles or that can be cut on the fold.
|
||||||
|
|
||||||
|
## Signature
|
||||||
|
|
||||||
|
```js
|
||||||
|
const settings = {
|
||||||
|
Boolean expand=true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The default `expand` setting is `true`.
|
||||||
|
Set this to `false` to draft a pattern with omitted or abbreviated parts,
|
||||||
|
rather than with fully-drawn parts.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Aaron } from '@freesewing/aaron'
|
||||||
|
|
||||||
|
const pattern = new Aaron({
|
||||||
|
expand: false,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
The `expand` setting does not automatically cause pattern parts to
|
||||||
|
be omitted or abbreviated.
|
||||||
|
Instead, it is up to the pattern designer to have the design
|
||||||
|
check for the `expand` setting,
|
||||||
|
include all, full parts if set to `true`,
|
||||||
|
and omit or abbreviate relevant parts if set to `false`.
|
|
@ -13,6 +13,7 @@ Object settings = {
|
||||||
Object absoluteOptions,
|
Object absoluteOptions,
|
||||||
Boolean complete=true,
|
Boolean complete=true,
|
||||||
Boolean embed=false,
|
Boolean embed=false,
|
||||||
|
Boolean expand=true,
|
||||||
String idPrefix='fs-',
|
String idPrefix='fs-',
|
||||||
Object|Boolean layout=true,
|
Object|Boolean layout=true,
|
||||||
String locale='en',
|
String locale='en',
|
||||||
|
@ -51,4 +52,3 @@ new pattern([
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ However, in our own UI on FreeSewing.org, we use this mechanism to allow
|
||||||
designer to flag information to the user, and even suggest changes to the
|
designer to flag information to the user, and even suggest changes to the
|
||||||
pattern configuration.
|
pattern configuration.
|
||||||
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -23,4 +22,8 @@ undefined Store.flag.error({
|
||||||
|
|
||||||
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
||||||
|
|
||||||
For a more detailed example of how we use this, see [flag.info()](/reference/store-methods/flag.info).
|
:::note RELATED
|
||||||
|
The above Signature contains abbreviated information.
|
||||||
|
For full details about this method's Signature, Configuration, and
|
||||||
|
Example usage, see [flag.info()](/reference/store-methods/flag.info).
|
||||||
|
:::
|
||||||
|
|
|
@ -11,7 +11,6 @@ However, in our own UI on FreeSewing.org, we use this mechanism to allow
|
||||||
designer to flag information to the user, and even suggest changes to the
|
designer to flag information to the user, and even suggest changes to the
|
||||||
pattern configuration.
|
pattern configuration.
|
||||||
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -23,4 +22,8 @@ undefined Store.flag.fixme({
|
||||||
|
|
||||||
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
||||||
|
|
||||||
For a more detailed example of how we use this, see [flag.info()](/reference/store-methods/flag.info).
|
:::note RELATED
|
||||||
|
The above Signature contains abbreviated information.
|
||||||
|
For full details about this method's Signature, Configuration, and
|
||||||
|
Example usage, see [flag.info()](/reference/store-methods/flag.info).
|
||||||
|
:::
|
||||||
|
|
|
@ -11,17 +11,28 @@ However, in our own UI on FreeSewing.org, we use this mechanism to allow
|
||||||
designer to flag information to the user, and even suggest changes to the
|
designer to flag information to the user, and even suggest changes to the
|
||||||
pattern configuration.
|
pattern configuration.
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
The Signature, Configuration, and Example information below applies to the
|
||||||
|
`flag.error()`, `flag.fixme()`, `flag.info()`, `flag.note()`,
|
||||||
|
`flag.tip()`, and `flag.warn()` methods.
|
||||||
|
:::
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
undefined Store.flag.info({
|
undefined Store.flag.info({
|
||||||
|
id: 'id_string',
|
||||||
title: 'flag:expandIsOn.t',
|
title: 'flag:expandIsOn.t',
|
||||||
desc: 'flag:expandIsOn.d',
|
desc: 'flag:expandIsOn.d',
|
||||||
|
msg: 'flag:expandIsOn',
|
||||||
notes: [
|
notes: [
|
||||||
'sorcha:moreInfo1',
|
'sorcha:moreInfo1',
|
||||||
'sorcha:moreInfo2',
|
'sorcha:moreInfo2',
|
||||||
],
|
],
|
||||||
|
replace: {
|
||||||
|
key1: //code for replacement value,
|
||||||
|
key2: //code for replacement value,
|
||||||
|
},
|
||||||
suggest: {
|
suggest: {
|
||||||
text: 'flag:disable',
|
text: 'flag:disable',
|
||||||
icon: 'expand',
|
icon: 'expand',
|
||||||
|
@ -38,11 +49,13 @@ The example above is from our implementation, which uses the following propertie
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ----------:| ------------------- | ----------- |
|
| ------------------------: | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `id` | String | An ID for this flag message. If none is provided, `title` will be used |
|
| `id` | String | An ID for this flag message. If none is provided, `title` will be used |
|
||||||
| `title` | String | The title of the message |
|
| `title` | String | The translation key for the title of the message |
|
||||||
| `desc` | String | The description of the message |
|
| `desc` | String | The translation key for the description of the message |
|
||||||
| `notes` | String or Array of Strings | More information/notes (see [Notes](#notes))|
|
| `msg` | String | The translation key for the message |
|
||||||
|
| `notes` | String or Array of Strings | Translation keys for more information/notes (see [Notes](#notes)) |
|
||||||
|
| `replace` | Object | Key/values for text replacements (see [Replacement Values](#replacement-values)) |
|
||||||
| `suggest.text` | String | Text to go on the button to implement the suggested configuration change |
|
| `suggest.text` | String | Text to go on the button to implement the suggested configuration change |
|
||||||
| `suggest.icon` | String | Icon name to go on the button to implement the suggested configuration change. (see [suggest.icon](#suggesticon)) |
|
| `suggest.icon` | String | Icon name to go on the button to implement the suggested configuration change. (see [suggest.icon](#suggesticon)) |
|
||||||
| `suggest.update.settings` | Array | An array describing the changes to apply to the `settings` if the user accepts the suggestion. (see [suggest.update](#suggestupdate)) |
|
| `suggest.update.settings` | Array | An array describing the changes to apply to the `settings` if the user accepts the suggestion. (see [suggest.update](#suggestupdate)) |
|
||||||
|
@ -52,14 +65,24 @@ The example above is from our implementation, which uses the following propertie
|
||||||
|
|
||||||
Notes are optional, but allow you to add more text/content to the flag message.
|
Notes are optional, but allow you to add more text/content to the flag message.
|
||||||
|
|
||||||
Unlike `desc` which can only hold a string, `notes` can hold either a string or an array of strings.
|
Unlike `title` or `desc` which can only hold a string, `notes` can hold either a string or an array of strings.
|
||||||
|
|
||||||
Both `desc` and `notes` will be rendered as markdown.
|
`notes` are also translation keys, and the translation strings will be
|
||||||
|
rendered as markdown.
|
||||||
|
|
||||||
|
### Replacement Values
|
||||||
|
|
||||||
|
The translation strings for `title`, `desc`, and `notes` can contain
|
||||||
|
variables that allow calculated values to be inserted into messages.
|
||||||
|
|
||||||
|
The optional `replace` object holds key/value pair properties where
|
||||||
|
keys are variable names and values contain code that generates
|
||||||
|
the replacement text for that variable.
|
||||||
|
|
||||||
### suggest.icon
|
### suggest.icon
|
||||||
|
|
||||||
An optional name of an icon. Or leave it out to not render and icon.
|
An optional name of an icon. Or leave it out to not render an icon.
|
||||||
The idea is that the icon helps convey the message, the following icon names are supported:
|
The idea is that the icon helps convey the message, with the following icon names supported:
|
||||||
|
|
||||||
- `note`
|
- `note`
|
||||||
- `info`
|
- `info`
|
||||||
|
@ -85,7 +108,7 @@ The `suggest.update` object has only two possible top-level keys:
|
||||||
They both take the same parameter, an array with two elements:
|
They both take the same parameter, an array with two elements:
|
||||||
|
|
||||||
```mjs
|
```mjs
|
||||||
Array [`path`, `value`]
|
Array[(`path`, `value`)]
|
||||||
```
|
```
|
||||||
|
|
||||||
This will be used to update the `settings` of the pattern, or the `ui` settings on FreeSewing.org.
|
This will be used to update the `settings` of the pattern, or the `ui` settings on FreeSewing.org.
|
||||||
|
@ -109,7 +132,7 @@ So to set the `waistEase` option to `0.2`, it should look like this:
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
({ store, part }) => {
|
;({ store, part }) => {
|
||||||
store.flag.info({
|
store.flag.info({
|
||||||
msg: `aaron:cutNeckBinding`,
|
msg: `aaron:cutNeckBinding`,
|
||||||
notes: ['flag:saUnused', 'flag:partHiddenByExpand'],
|
notes: ['flag:saUnused', 'flag:partHiddenByExpand'],
|
||||||
|
@ -129,4 +152,3 @@ So to set the `waistEase` option to `0.2`, it should look like this:
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ However, in our own UI on FreeSewing.org, we use this mechanism to allow
|
||||||
designer to flag information to the user, and even suggest changes to the
|
designer to flag information to the user, and even suggest changes to the
|
||||||
pattern configuration.
|
pattern configuration.
|
||||||
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -23,4 +22,8 @@ undefined Store.flag.note({
|
||||||
|
|
||||||
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
||||||
|
|
||||||
For a more detailed example of how we use this, see [flag.info()](/reference/store-methods/flag.info).
|
:::note RELATED
|
||||||
|
The above Signature contains abbreviated information.
|
||||||
|
For full details about this method's Signature, Configuration, and
|
||||||
|
Example usage, see [flag.info()](/reference/store-methods/flag.info).
|
||||||
|
:::
|
||||||
|
|
|
@ -23,19 +23,15 @@ The example above is from our implementation, which uses the following propertie
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ----------:| ------------------- | ----------- |
|
| -------: | ------ | ---------------------------- |
|
||||||
| `preset` | String | The ID of an existing preset |
|
| `preset` | String | The ID of an existing preset |
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
({ store, expand, part }) => {
|
;({ store, expand, part }) => {
|
||||||
store.flag.preset(expand
|
store.flag.preset(expand ? 'expandIsOn' : 'expandIsOff')
|
||||||
? 'expandIsOn'
|
|
||||||
: 'expandIsOff'
|
|
||||||
)
|
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ However, in our own UI on FreeSewing.org, we use this mechanism to allow
|
||||||
designer to flag information to the user, and even suggest changes to the
|
designer to flag information to the user, and even suggest changes to the
|
||||||
pattern configuration.
|
pattern configuration.
|
||||||
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -23,4 +22,8 @@ undefined Store.flag.tip({
|
||||||
|
|
||||||
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
||||||
|
|
||||||
For a more detailed example of how we use this, see [flag.info()](/reference/store-methods/flag.info).
|
:::note RELATED
|
||||||
|
The above Signature contains abbreviated information.
|
||||||
|
For full details about this method's Signature, Configuration, and
|
||||||
|
Example usage, see [flag.info()](/reference/store-methods/flag.info).
|
||||||
|
:::
|
||||||
|
|
|
@ -11,7 +11,6 @@ However, in our own UI on FreeSewing.org, we use this mechanism to allow
|
||||||
designer to flag information to the user, and even suggest changes to the
|
designer to flag information to the user, and even suggest changes to the
|
||||||
pattern configuration.
|
pattern configuration.
|
||||||
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -23,4 +22,8 @@ undefined Store.flag.warn({
|
||||||
|
|
||||||
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
Since these methods are not part of FreeSewing's core API, what you pass to this method does depend on your own implementation.
|
||||||
|
|
||||||
For a more detailed example of how we use this, see [flag.info()](/reference/store-methods/flag.info).
|
:::note RELATED
|
||||||
|
The above Signature contains abbreviated information.
|
||||||
|
For full details about this method's Signature, Configuration, and
|
||||||
|
Example usage, see [flag.info()](/reference/store-methods/flag.info).
|
||||||
|
:::
|
||||||
|
|
|
@ -16,9 +16,6 @@ via a web browser.
|
||||||
The files and computer programs are hosted on and run from a remote
|
The files and computer programs are hosted on and run from a remote
|
||||||
server run by GitHub.
|
server run by GitHub.
|
||||||
|
|
||||||
[gh]: https://github.com
|
|
||||||
[ghcs]: https://github.com/features/codespaces
|
|
||||||
|
|
||||||
For FreeSewing, you can use Codespaces to edit our repository files to
|
For FreeSewing, you can use Codespaces to edit our repository files to
|
||||||
modify existing designs, add new files to create new designs, and run
|
modify existing designs, add new files to create new designs, and run
|
||||||
the FreeSewing lab website so you can test designs.
|
the FreeSewing lab website so you can test designs.
|
||||||
|
@ -55,7 +52,7 @@ The Codespaces app will open in the browser window.
|
||||||
The Codespaces app is basically the [Visual Studio Code][vs] app with
|
The Codespaces app is basically the [Visual Studio Code][vs] app with
|
||||||
Codespaces and GitHub integration built in.
|
Codespaces and GitHub integration built in.
|
||||||
|
|
||||||
[vs]: https://code.visualstudio.com 'Wait 45 seconds or so for the Codespace app to clone the repository from
|
'Wait 45 seconds or so for the Codespace app to clone the repository from
|
||||||
GitHub to the codespace repository and start.'
|
GitHub to the codespace repository and start.'
|
||||||
|
|
||||||
## Editing files
|
## Editing files
|
||||||
|
@ -234,8 +231,14 @@ To delete a codespace:
|
||||||
and select "Delete".
|
and select "Delete".
|
||||||
|
|
||||||
:::note RELATED
|
:::note RELATED
|
||||||
|
|
||||||
For more information, please see:
|
For more information, please see:
|
||||||
|
|
||||||
- [GitHub Codebases documentation](https://docs.github.com/en/codespaces).
|
- [GitHub Codebases documentation](https://docs.github.com/en/codespaces).
|
||||||
- [About billing for GitHub Codespaces](https://docs.github.com/en/billing/managing-billing-for-github-codespaces/about-billing-for-github-codespaces)
|
- [About billing for GitHub Codespaces](https://docs.github.com/en/billing/managing-billing-for-github-codespaces/about-billing-for-github-codespaces)
|
||||||
:::
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
[gh]: https://github.com
|
||||||
|
[ghcs]: https://github.com/features/codespaces
|
||||||
|
[vs]: https://code.visualstudio.com
|
||||||
|
|
|
@ -3,17 +3,16 @@ title: Setting up the FreeSewing development environment
|
||||||
sidebar_position: 40
|
sidebar_position: 40
|
||||||
---
|
---
|
||||||
|
|
||||||
FreeSewing provides a development environment to help you design and develop
|
FreeSewing provides the studio, a development environment to help you design and develop patterns.
|
||||||
patterns.
|
|
||||||
|
|
||||||
There are two ways to run this development environment:
|
There are two ways to run this studio:
|
||||||
|
|
||||||
- [**Monorepo development**](#monorepo-development): Use this if you intend to
|
- [**Repository studio**](#monorepo-studio): Use this if you intend to
|
||||||
contribute your work to FreeSewing
|
contribute your work to FreeSewing
|
||||||
- [**Stand-alone development**](#stand-alone-development): Use this if you want
|
- [**Stand-alone studio**](#stand-alone-studio): Use this if you want
|
||||||
to do your own thing, and not contribute to FreeSewing
|
to do your own thing, and not contribute to FreeSewing
|
||||||
|
|
||||||
## Monorepo development
|
## Repository studio
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
This is the recommended way for (aspiring) FreeSewing contributors
|
This is the recommended way for (aspiring) FreeSewing contributors
|
||||||
|
@ -22,34 +21,28 @@ This is the recommended way for (aspiring) FreeSewing contributors
|
||||||
### TL;DR
|
### TL;DR
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/freesewing/freesewing
|
git clone https://codeberg.org/freesewing/freesewing.git
|
||||||
cd freesewing
|
cd freesewing
|
||||||
yarn kickstart
|
npm run kickstart
|
||||||
```
|
```
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Even better: [clone your own
|
Even better: [clone your own
|
||||||
fork](https://github.com/freesewing/freesewing/fork)
|
fork](https://codeberg.org/freesewing/freesewing/fork)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/your-username/freesewing
|
git clone https://codeberg.org/your-username/freesewing.git
|
||||||
cd freesewing
|
cd freesewing
|
||||||
yarn kickstart
|
npm run kickstart
|
||||||
```
|
```
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
This sets up the monorepo. If you would like to create a new design, run the
|
This sets up the monorepo. If you would like to create a new design or plugin, run the
|
||||||
following command:
|
following command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn new design
|
npm run add
|
||||||
```
|
|
||||||
|
|
||||||
If you'd like to create a new plugin, run this variant instead:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
yarn new plugin
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step by step
|
### Step by step
|
||||||
|
@ -59,20 +52,10 @@ These docs assume you have git installed.
|
||||||
But if you're running Linux, you have git, right?
|
But if you're running Linux, you have git, right?
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Install yarn
|
|
||||||
|
|
||||||
Our repository uses yarn workspaces. So you'll need `yarn` to work with it.
|
|
||||||
|
|
||||||
To install it run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install yarn --global
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Fork our repository
|
#### Fork our repository
|
||||||
|
|
||||||
You'll want to fork our repository. This way you have your own copy where you can make
|
You'll want to fork our repository. This way you have your own copy where you can make
|
||||||
all the changes you want. To do so, visit https://github.com/freesewing/freesewing/fork
|
all the changes you want. To do so, visit https://codeberg.org/freesewing/freesewing/fork
|
||||||
|
|
||||||
#### Clone the forked repository
|
#### Clone the forked repository
|
||||||
|
|
||||||
|
@ -82,96 +65,76 @@ Now that you have your very own fork, it's time to clone it locally.
|
||||||
git clone <url to your fork>
|
git clone <url to your fork>
|
||||||
```
|
```
|
||||||
|
|
||||||
Make sure to use the URL to your own fork, typically `https://github.com/your-username/freesewing` but
|
Make sure to use the URL to your own fork, typically `https://codeberg.org/your-username/freesewing.git` but
|
||||||
obviously with your real username rather than `your-username`.
|
obviously with your real username rather than `your-username`.
|
||||||
|
|
||||||
#### Install dependencies
|
#### Install dependencies
|
||||||
|
|
||||||
Enter the directory that was created, and run the `yarn kickstart` command:
|
Enter the directory that was created, and run the `npm run kickstart` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd freesewing
|
cd freesewing
|
||||||
yarn kickstart
|
npm run kickstart
|
||||||
```
|
```
|
||||||
|
|
||||||
Now you're ready to [start the development environment](/tutorials/getting-started-linux/dev-start).
|
Now you're ready to [start the development environment](/tutorials/getting-started-linux/dev-start).
|
||||||
|
|
||||||
:::note
|
### Creating a new design or plugin
|
||||||
|
|
||||||
There is another `yarn` command that comes with some Linux distributions,
|
If you would like to create a new design or plugin, run the following command:
|
||||||
installed as part of the `cmdtest` package and used for command line
|
|
||||||
scenario testing.
|
|
||||||
If you get an `ERROR: There are no scenarios; must have at least one.`
|
|
||||||
message when trying to run the `yarn` command, it may be because the wrong
|
|
||||||
`yarn` is being used.
|
|
||||||
|
|
||||||
Possible workarounds for this include uninstalling the `cmdtest` package
|
|
||||||
or making sure that npm `yarn` is installed and comes first in your `PATH`
|
|
||||||
environment variable.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Creating a new design
|
|
||||||
|
|
||||||
If you would like to create a new design, run the following command:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn new design
|
npm run add
|
||||||
```
|
```
|
||||||
|
|
||||||
## Creating a new plugin
|
After you've answered [some questions](#questions), it create a new
|
||||||
|
sub-folder for your design in the `designs` folder.
|
||||||
|
|
||||||
If you'd like to create a new plugin, run the following command:
|
Now you're ready to [start the development
|
||||||
|
environment](/tutorials/getting-started-linux/dev-start).
|
||||||
```sh
|
|
||||||
yarn new plugin
|
|
||||||
```
|
|
||||||
|
|
||||||
## Stand-alone development
|
## Stand-alone development
|
||||||
|
|
||||||
With Node.js installed, all you need to do to setup the stand-alone development environment is run this command:
|
With Node.js installed, all you need to do to setup the stand-alone development environment is run this command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx @freesewing/new-design
|
npx @freesewing/studio
|
||||||
```
|
```
|
||||||
|
|
||||||
After you've answered [some questions](#questions), it will take a while to set
|
After you enter the folder name to create, it will take a while to set
|
||||||
everything up. When it's done, you will have a new folder with the development
|
everything up. When it's done, you will have a new folder with the development
|
||||||
environment inside.
|
environment inside.
|
||||||
|
|
||||||
|
### Creating a new design
|
||||||
|
|
||||||
|
If you would like to create a new design, enter the folder that was just created and run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run add
|
||||||
|
```
|
||||||
|
|
||||||
|
After you've answered [some questions](#questions), it create a new
|
||||||
|
sub-folder for your design in the `designs` folder.
|
||||||
|
|
||||||
Now you're ready to [start the development
|
Now you're ready to [start the development
|
||||||
environment](/tutorials/getting-started-linux/dev-start).
|
environment](/tutorials/getting-started-linux/dev-start).
|
||||||
|
|
||||||
:::tip
|
|
||||||
The folder will have the name you chose above.
|
|
||||||
:::
|
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
### Questions
|
### Questions
|
||||||
|
|
||||||
|
#### What design name to use
|
||||||
|
|
||||||
|
Please stick to a single word name using \[a-z] to avoid problems.
|
||||||
|
|
||||||
#### What template to use
|
#### What template to use
|
||||||
|
|
||||||
Use `From scratch` unless you want to start from our of our blocks:
|
Use `From scratch` unless you want to start from our of our blocks:
|
||||||
|
|
||||||
- Use `Extend Brian` to start from [Brian](https://freesewing.org/designs/brian)
|
- Use `Extend Brian` to start from [Brian](https://freesewing.eu/designs/brian)
|
||||||
- Use `Extend Bent` to start from [Bent](https://freesewing.org/designs/bent)
|
- Use `Extend Bent` to start from [Bent](https://freesewing.eu/designs/bent)
|
||||||
- Use `Extend Bella` to start from [Bella](https://freesewing.org/designs/bella)
|
- Use `Extend Bella` to start from [Bella](https://freesewing.eu/designs/bella)
|
||||||
- Use `Extend Breanna` to start from [Breanna](https://freesewing.org/designs/breanna)
|
- Use `Extend Breanna` to start from [Breanna](https://freesewing.eu/designs/breanna)
|
||||||
- Use `Extend Titan` to start from [Titan](https://freesewing.org/designs/titan)
|
- Use `Extend Titan` to start from [Titan](https://freesewing.eu/designs/titan)
|
||||||
|
|
||||||
#### What name to use
|
|
||||||
|
|
||||||
This will become the name of your design. Stick to \[a-z] here to avoid problems.
|
|
||||||
|
|
||||||
If you're not certain what to pick, just mash some keys, it doesn't matter.
|
|
||||||
|
|
||||||
#### What package manager to use
|
|
||||||
|
|
||||||
You may wish to choose `yarn` since that is the package manager
|
|
||||||
that we use when doing work in the monorepo,
|
|
||||||
and many of our tutorials are written to use `yarn`.
|
|
||||||
However, it doesn't really matter.
|
|
||||||
You can choose either `yarn` or `npm` as you wish.
|
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
|
@ -3,55 +3,70 @@ title: Start the development environment
|
||||||
sidebar_position: 50
|
sidebar_position: 50
|
||||||
---
|
---
|
||||||
|
|
||||||
FreeSewing provides a development environment to help you design and develop patterns.
|
FreeSewing provides the studio, a development environment to help you design and develop patterns.
|
||||||
|
|
||||||
There are two ways to run this development environment:
|
There are two ways to run this studio:
|
||||||
|
|
||||||
- [**Monorepo development**](#monorepo-development): Use this if you intend to contribute your work to FreeSewing
|
- [**Repository studio**](#repository-studio): Use this if you intend to contribute your work to FreeSewing
|
||||||
- [**Stand-alone development**](#stand-alone-development): Use this if you want to do your own thing, and not contribute to FreeSewing
|
- [**Stand-alone studio**](#stand-alone-studio): Use this if you want to do your own thing, and not contribute to FreeSewing
|
||||||
|
|
||||||
## Monorepo development
|
## Repository Studio
|
||||||
|
|
||||||
Run `yarn lab` to start the development environment:
|
Run `npm run studio` to start the repository studio development environment:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn lab
|
npm run studio
|
||||||
```
|
```
|
||||||
|
|
||||||
Then point your browser to http://localhost:8000
|
Then point your browser to http://localhost:3000
|
||||||
|
|
||||||
|
Your new design will appear in the Local Designs page.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
|
|
||||||
### Adding a new design
|
### Adding another new design
|
||||||
|
|
||||||
This is all you need to work on existing designs. If you'd like to add a new design, run:
|
This is all you need to work on existing designs. If you'd like to add another new design, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn new design
|
npm run add
|
||||||
```
|
```
|
||||||
|
|
||||||
Just make sure to re-start the lab afterwards with `yarn lab`
|
Just make sure to re-start the repository studio afterwards with `npm run studio`
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Stand-alone development
|
## Stand-alone studio
|
||||||
|
|
||||||
You will have a new folder that has the name you picked for your design.
|
You will have a new folder that contains the stand-alone studio development environment.
|
||||||
If you chose `test`, you will have a folder named `test`.
|
(Within this new folder, the `design` subfolder holds your design's configuration files and source code.
|
||||||
If you chose `banana`, you'll have a folder named `banana`.
|
|
||||||
(Within this new folder, the `design` subfolder holds your design's configuration file and source code.
|
|
||||||
You can ignore all other subfolders and files; they are part of the development environment.)
|
You can ignore all other subfolders and files; they are part of the development environment.)
|
||||||
|
|
||||||
To start the development environment, enter the folder that was created
|
To start the development environment, enter the folder that was created
|
||||||
and run `yarn dev` (or `npm run dev` if you're using npm as a package manager).
|
and run `npm run start`.
|
||||||
|
|
||||||
Then open your browser and go to http://localhost:8000
|
```bash
|
||||||
|
npm run start
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open your browser and go to http://localhost:3000
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
The development environment will watch for any changes you make to
|
The development environment will watch for any changes you make to
|
||||||
the pattern's source code or configuration.
|
the pattern's source code or configuration.
|
||||||
When you do, it will update automatically in your browser.
|
When you do, the pattern will update automatically in your browser.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
### Adding another new design
|
||||||
|
|
||||||
|
This is all you need to work on existing designs. If you'd like to add another new design, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run add
|
||||||
|
```
|
||||||
|
|
||||||
|
Just make sure to re-start the stand-alone studio afterwards with `npm run start`.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
##### Yay, you're done!
|
##### Yay, you're done!
|
||||||
|
|
|
@ -6,10 +6,10 @@ sidebar_position: 20
|
||||||
Now we will use `nvm` to install Node.js. Run the following command:
|
Now we will use `nvm` to install Node.js. Run the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nvm install lts/hydrogen
|
nvm install lts/iron
|
||||||
```
|
```
|
||||||
|
|
||||||
This will install the so-called LTS version of Node.js 18 on your system.
|
This will install the so-called LTS version of Node.js 20 on your system.
|
||||||
|
|
||||||
LTS versions -- short for Long Term Support -- are good Node.js versions
|
LTS versions -- short for Long Term Support -- are good Node.js versions
|
||||||
to use because they are stable and supported for a long time.
|
to use because they are stable and supported for a long time.
|
||||||
|
|
|
@ -47,7 +47,7 @@ With multiple Node.js versions installed, `nvm` allows you to switch between dif
|
||||||
versions. Just tell it which version you want to use:
|
versions. Just tell it which version you want to use:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nvm use lts/hydrogen
|
nvm use lts/iron
|
||||||
```
|
```
|
||||||
|
|
||||||
If you picked a version that is not installed, `nvm` will simply tell you
|
If you picked a version that is not installed, `nvm` will simply tell you
|
||||||
|
|
|
@ -3,17 +3,16 @@ title: Setting up the FreeSewing development environment
|
||||||
sidebar_position: 40
|
sidebar_position: 40
|
||||||
---
|
---
|
||||||
|
|
||||||
FreeSewing provides a development environment to help you design and develop
|
FreeSewing provides the studio, a development environment to help you design and develop patterns.
|
||||||
patterns.
|
|
||||||
|
|
||||||
There are two ways to run this development environment:
|
There are two ways to run this studio:
|
||||||
|
|
||||||
- [**Monorepo development**](#monorepo-development): Use this if you intend to
|
- [**Repository studio**](#monorepo-studio): Use this if you intend to
|
||||||
contribute your work to FreeSewing
|
contribute your work to FreeSewing
|
||||||
- [**Stand-alone development**](#stand-alone-development): Use this if you want
|
- [**Stand-alone studio**](#stand-alone-studio): Use this if you want
|
||||||
to do your own thing, and not contribute to FreeSewing
|
to do your own thing, and not contribute to FreeSewing
|
||||||
|
|
||||||
## Monorepo development
|
## Repository studio
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
This is the recommended way for (aspiring) FreeSewing contributors
|
This is the recommended way for (aspiring) FreeSewing contributors
|
||||||
|
@ -22,57 +21,41 @@ This is the recommended way for (aspiring) FreeSewing contributors
|
||||||
### TL;DR
|
### TL;DR
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/freesewing/freesewing
|
git clone https://codeberg.org/freesewing/freesewing.git
|
||||||
cd freesewing
|
cd freesewing
|
||||||
yarn kickstart
|
npm run kickstart
|
||||||
```
|
```
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Even better: [clone your own
|
Even better: [clone your own
|
||||||
fork](https://github.com/freesewing/freesewing/fork)
|
fork](https://codeberg.org/freesewing/freesewing/fork)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/your-username/freesewing
|
git clone https://codeberg.org/your-username/freesewing.git
|
||||||
cd freesewing
|
cd freesewing
|
||||||
yarn kickstart
|
npm run kickstart
|
||||||
```
|
```
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
This sets up the monorepo. If you would like to create a new design, run the
|
This sets up the monorepo. If you would like to create a new design or plugin, run the
|
||||||
following command:
|
following command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn new design
|
npm run add
|
||||||
```
|
|
||||||
|
|
||||||
If you'd like to create a new plugin, run this variant instead:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
yarn new plugin
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step by step
|
### Step by step
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
These docs assume you have git installed.
|
These docs assume you have git installed.
|
||||||
But if you're running macOS, you have git, right?
|
But if you're running on a Mac system, you have git, right?
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Install yarn
|
|
||||||
|
|
||||||
Our repository uses yarn workspaces. So you'll need `yarn` to work with it.
|
|
||||||
|
|
||||||
To install it run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install yarn --global
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Fork our repository
|
#### Fork our repository
|
||||||
|
|
||||||
You'll want to fork our repository. This way you have your own copy where you can make
|
You'll want to fork our repository. This way you have your own copy where you can make
|
||||||
all the changes you want. To do so, visit https://github.com/freesewing/freesewing/fork
|
all the changes you want. To do so, visit https://codeberg.org/freesewing/freesewing/fork
|
||||||
|
|
||||||
#### Clone the forked repository
|
#### Clone the forked repository
|
||||||
|
|
||||||
|
@ -82,81 +65,76 @@ Now that you have your very own fork, it's time to clone it locally.
|
||||||
git clone <url to your fork>
|
git clone <url to your fork>
|
||||||
```
|
```
|
||||||
|
|
||||||
Make sure to use the URL to your own fork, typically `https://github.com/your-username/freesewing` but
|
Make sure to use the URL to your own fork, typically `https://codeberg.org/your-username/freesewing.git` but
|
||||||
obviously with your real username rather than `your-username`.
|
obviously with your real username rather than `your-username`.
|
||||||
|
|
||||||
#### Install dependencies
|
#### Install dependencies
|
||||||
|
|
||||||
Enter the directory that was created, and run the `yarn kickstart` command:
|
Enter the directory that was created, and run the `npm run kickstart` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd freesewing
|
cd freesewing
|
||||||
yarn kickstart
|
npm run kickstart
|
||||||
```
|
```
|
||||||
|
|
||||||
Now you're ready to [start the development environment](/tutorials/getting-started-linux/dev-start).
|
Now you're ready to [start the development environment](/tutorials/getting-started-linux/dev-start).
|
||||||
|
|
||||||
## Creating a new design
|
### Creating a new design or plugin
|
||||||
|
|
||||||
If you would like to create a new design, run the following command:
|
If you would like to create a new design or plugin, run the following command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn new design
|
npm run add
|
||||||
```
|
```
|
||||||
|
|
||||||
## Creating a new plugin
|
After you've answered [some questions](#questions), it create a new
|
||||||
|
sub-folder for your design in the `designs` folder.
|
||||||
|
|
||||||
If you'd like to create a new plugin, run the following command:
|
Now you're ready to [start the development
|
||||||
|
environment](/tutorials/getting-started-mac/dev-start).
|
||||||
```sh
|
|
||||||
yarn new plugin
|
|
||||||
```
|
|
||||||
|
|
||||||
## Stand-alone development
|
## Stand-alone development
|
||||||
|
|
||||||
With Node.js installed, all you need to do to setup the stand-alone development environment is run this command:
|
With Node.js installed, all you need to do to setup the stand-alone development environment is run this command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx @freesewing/new-design
|
npx @freesewing/studio
|
||||||
```
|
```
|
||||||
|
|
||||||
After you've answered [some questions](#questions), it will take a while to set
|
After you enter the folder name to create, it will take a while to set
|
||||||
everything up. When it's done, you will have a new folder with the development
|
everything up. When it's done, you will have a new folder with the development
|
||||||
environment inside.
|
environment inside.
|
||||||
|
|
||||||
Now you're ready to [start the development
|
### Creating a new design
|
||||||
environment](/tutorials/getting-started-linux/dev-start).
|
|
||||||
|
|
||||||
:::tip
|
If you would like to create a new design, enter the folder that was just created and run the following command:
|
||||||
The folder will have the name you chose above.
|
|
||||||
:::
|
```sh
|
||||||
|
npm run add
|
||||||
|
```
|
||||||
|
|
||||||
|
After you've answered [some questions](#questions), it create a new
|
||||||
|
sub-folder for your design in the `designs` folder.
|
||||||
|
|
||||||
|
Now you're ready to [start the development
|
||||||
|
environment](/tutorials/getting-started-mac/dev-start).
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
### Questions
|
### Questions
|
||||||
|
|
||||||
|
#### What design name to use
|
||||||
|
|
||||||
|
Please stick to a single word name using \[a-z] to avoid problems.
|
||||||
|
|
||||||
#### What template to use
|
#### What template to use
|
||||||
|
|
||||||
Use `From scratch` unless you want to start from our of our blocks:
|
Use `From scratch` unless you want to start from our of our blocks:
|
||||||
|
|
||||||
- Use `Extend Brian` to start from [Brian](https://freesewing.org/designs/brian)
|
- Use `Extend Brian` to start from [Brian](https://freesewing.eu/designs/brian)
|
||||||
- Use `Extend Bent` to start from [Bent](https://freesewing.org/designs/bent)
|
- Use `Extend Bent` to start from [Bent](https://freesewing.eu/designs/bent)
|
||||||
- Use `Extend Bella` to start from [Bella](https://freesewing.org/designs/bella)
|
- Use `Extend Bella` to start from [Bella](https://freesewing.eu/designs/bella)
|
||||||
- Use `Extend Breanna` to start from [Breanna](https://freesewing.org/designs/breanna)
|
- Use `Extend Breanna` to start from [Breanna](https://freesewing.eu/designs/breanna)
|
||||||
- Use `Extend Titan` to start from [Titan](https://freesewing.org/designs/titan)
|
- Use `Extend Titan` to start from [Titan](https://freesewing.eu/designs/titan)
|
||||||
|
|
||||||
#### What name to use
|
|
||||||
|
|
||||||
This will become the name of your design. Stick to \[a-z] here to avoid problems.
|
|
||||||
|
|
||||||
If you're not certain what to pick, just mash some keys, it doesn't matter.
|
|
||||||
|
|
||||||
#### What package manager to use
|
|
||||||
|
|
||||||
You may wish to choose `yarn` since that is the package manager
|
|
||||||
that we use when doing work in the monorepo,
|
|
||||||
and many of our tutorials are written to use `yarn`.
|
|
||||||
However, it doesn't really matter.
|
|
||||||
You can choose either `yarn` or `npm` as you wish.
|
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
|
@ -3,55 +3,70 @@ title: Start the development environment
|
||||||
sidebar_position: 50
|
sidebar_position: 50
|
||||||
---
|
---
|
||||||
|
|
||||||
FreeSewing provides a development environment to help you design and develop patterns.
|
FreeSewing provides the studio, a development environment to help you design and develop patterns.
|
||||||
|
|
||||||
There are two ways to run this development environment:
|
There are two ways to run this studio:
|
||||||
|
|
||||||
- [**Monorepo development**](#monorepo-development): Use this if you intend to contribute your work to FreeSewing
|
- [**Repository studio**](#repository-studio): Use this if you intend to contribute your work to FreeSewing
|
||||||
- [**Stand-alone development**](#stand-alone-development): Use this if you want to do your own thing, and not contribute to FreeSewing
|
- [**Stand-alone studio**](#stand-alone-studio): Use this if you want to do your own thing, and not contribute to FreeSewing
|
||||||
|
|
||||||
## Monorepo development
|
## Repository Studio
|
||||||
|
|
||||||
Run `yarn lab` to start the development environment:
|
Run `npm run studio` to start the repository studio development environment:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn lab
|
npm run studio
|
||||||
```
|
```
|
||||||
|
|
||||||
Then point your browser to http://localhost:8000
|
Then point your browser to http://localhost:3000
|
||||||
|
|
||||||
|
Your new design will appear in the Local Designs page.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
|
|
||||||
### Adding a new design
|
### Adding another new design
|
||||||
|
|
||||||
This is all you need to work on existing designs. If you'd like to add a new design, run:
|
This is all you need to work on existing designs. If you'd like to add another new design, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn new design
|
npm run add
|
||||||
```
|
```
|
||||||
|
|
||||||
Just make sure to re-start the lab afterwards with `yarn lab`
|
Just make sure to re-start the repository studio afterwards with `npm run studio`
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Stand-alone development
|
## Stand-alone studio
|
||||||
|
|
||||||
You will have a new folder that has the name you picked for your design.
|
You will have a new folder that contains the stand-alone studio development environment.
|
||||||
If you chose `test`, you will have a folder named `test`.
|
(Within this new folder, the `design` subfolder holds your design's configuration files and source code.
|
||||||
If you chose `banana`, you'll have a folder named `banana`.
|
|
||||||
(Within this new folder, the `design` subfolder holds your design's configuration file and source code.
|
|
||||||
You can ignore all other subfolders and files; they are part of the development environment.)
|
You can ignore all other subfolders and files; they are part of the development environment.)
|
||||||
|
|
||||||
To start the development environment, enter the folder that was created
|
To start the development environment, enter the folder that was created
|
||||||
and run `yarn dev` (or `npm run dev` if you're using npm as a package manager).
|
and run `npm run start`.
|
||||||
|
|
||||||
Then open your browser and go to http://localhost:8000
|
```bash
|
||||||
|
npm run start
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open your browser and go to http://localhost:3000
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
The development environment will watch for any changes you make to
|
The development environment will watch for any changes you make to
|
||||||
the pattern's source code or configuration.
|
the pattern's source code or configuration.
|
||||||
When you do, it will update automatically in your browser.
|
When you do, the pattern will update automatically in your browser.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
### Adding another new design
|
||||||
|
|
||||||
|
This is all you need to work on existing designs. If you'd like to add another new design, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run add
|
||||||
|
```
|
||||||
|
|
||||||
|
Just make sure to re-start the stand-alone studio afterwards with `npm run start`.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
##### Yay, you're done!
|
##### Yay, you're done!
|
||||||
|
|
|
@ -6,10 +6,10 @@ sidebar_position: 20
|
||||||
Now we will use `nvm` to install Node.js. Run the following command:
|
Now we will use `nvm` to install Node.js. Run the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nvm install lts/hydrogen
|
nvm install lts/iron
|
||||||
```
|
```
|
||||||
|
|
||||||
This will install the so-called LTS version of Node.js 18 on your system.
|
This will install the so-called LTS version of Node.js 20 on your system.
|
||||||
|
|
||||||
LTS versions -- short for Long Term Support -- are good Node.js versions
|
LTS versions -- short for Long Term Support -- are good Node.js versions
|
||||||
to use because they are stable and supported for a long time.
|
to use because they are stable and supported for a long time.
|
||||||
|
|
|
@ -47,7 +47,7 @@ With multiple Node.js versions installed, `nvm` allows you to switch between dif
|
||||||
versions. Just tell it which version you want to use:
|
versions. Just tell it which version you want to use:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nvm use v10.22.1
|
nvm use lts/iron
|
||||||
```
|
```
|
||||||
|
|
||||||
If you picked a version that is not installed, `nvm` will simply tell you
|
If you picked a version that is not installed, `nvm` will simply tell you
|
||||||
|
|
|
@ -62,7 +62,7 @@ Free Hobby accounts are limited to 3 Projects per Git repository.
|
||||||
|
|
||||||
Under each project there will be many, many deployments.
|
Under each project there will be many, many deployments.
|
||||||
|
|
||||||
\_Deployments are simply builds, an instance of a website/app
|
_Deployments_ are simply builds, an instance of a website/app
|
||||||
built from a specific commit version of a specific branch of the repository.
|
built from a specific commit version of a specific branch of the repository.
|
||||||
These deployments can be accessed using a web browser to preview
|
These deployments can be accessed using a web browser to preview
|
||||||
the web app or website.
|
the web app or website.
|
||||||
|
|
|
@ -55,11 +55,11 @@ guide](https://github.com/nvm-sh/nvm#install--update-script). Once installed
|
||||||
you will need to activate NVM by either following the instructions printed to
|
you will need to activate NVM by either following the instructions printed to
|
||||||
the screen or opening a new terminal.
|
the screen or opening a new terminal.
|
||||||
|
|
||||||
#### Install Node.js (and optionally Yarn)
|
#### Install Node.js
|
||||||
|
|
||||||
Now that you have NVM installed, you can install Node.js. The latest version can be
|
Now that you have NVM installed, you can install Node.js. The latest version can be
|
||||||
installed using `nvm install default`. You can also install a specific version
|
installed using `nvm install default`. You can also install a specific version
|
||||||
using `nvm install v18.17.0`. For the purposes of debugging it can be useful to
|
using `nvm install v20.19.1`. For the purposes of debugging it can be useful to
|
||||||
have the same version of Node.js installed as the main project uses, which you can
|
have the same version of Node.js installed as the main project uses, which you can
|
||||||
then activate using `nvm use <version>`. You can determine what version the
|
then activate using `nvm use <version>`. You can determine what version the
|
||||||
FreeSewing project uses by checking
|
FreeSewing project uses by checking
|
||||||
|
@ -68,16 +68,12 @@ FreeSewing project uses by checking
|
||||||
:::warning
|
:::warning
|
||||||
At the time this guide was written the latest version of Node.js/npm has
|
At the time this guide was written the latest version of Node.js/npm has
|
||||||
a bug in the dependency resolution process which causes the freesewing project
|
a bug in the dependency resolution process which causes the freesewing project
|
||||||
to fail to build. Use the latest LTS version (currently 18.17.0) or the specific
|
to fail to build. Use the latest LTS version (currently 20.19.1) or the specific
|
||||||
version used by the main project to avoid this issue.
|
version used by the main project to avoid this issue.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Node.js comes with the Node Package Manager (npm) by default which can be used to
|
Node.js comes with the Node Package Manager (npm) by default which is used to
|
||||||
set up the project. The default package manager uses a fairly simplistic approach
|
set up the project.
|
||||||
to dependency resolution which can make builds take a long time. Yarn is an
|
|
||||||
alternative package manager which makes builds faster, especially for monolithic
|
|
||||||
projects like FreeSewing. If you'd like to install yarn run `npm install yarn
|
|
||||||
--global` (optional, but recommended).
|
|
||||||
|
|
||||||
#### Install and configure Git (recommended)
|
#### Install and configure Git (recommended)
|
||||||
|
|
||||||
|
@ -137,12 +133,12 @@ will take you to the latest release which provides an installer you can download
|
||||||
and run. Once nvm-windows is installed you will be able to continue with the
|
and run. Once nvm-windows is installed you will be able to continue with the
|
||||||
rest of this process.
|
rest of this process.
|
||||||
|
|
||||||
### Install Node.js (and optionally Yarn)
|
### Install Node.js
|
||||||
|
|
||||||
Open a Powershell terminal or command prompt. Run `nvm ls available` to show
|
Open a Powershell terminal or command prompt. Run `nvm ls available` to show
|
||||||
versions that can be installed. Choose the appropriate version (you should use
|
versions that can be installed. Choose the appropriate version (you should use
|
||||||
the same version as the freesewing project or latest LTS version) then run `nvm
|
the same version as the freesewing project or latest LTS version) then run `nvm
|
||||||
install 18.17.0` and `nvm use 18.17.0` (where `18.17.0` is the full version
|
install 20.19.1` and `nvm use 20.19.1` (where `20.19.1` is the full version
|
||||||
string of the version you wish to use) to activate the newly installed version.
|
string of the version you wish to use) to activate the newly installed version.
|
||||||
You will receive a prompt for elevated permissions and will need to accept it in
|
You will receive a prompt for elevated permissions and will need to accept it in
|
||||||
order to activate the new version of Node.js.
|
order to activate the new version of Node.js.
|
||||||
|
@ -150,20 +146,16 @@ order to activate the new version of Node.js.
|
||||||
:::warning
|
:::warning
|
||||||
At the time this guide was written the latest version of Node.js/npm has
|
At the time this guide was written the latest version of Node.js/npm has
|
||||||
a bug in the dependency resolution process which causes the freesewing project
|
a bug in the dependency resolution process which causes the freesewing project
|
||||||
to fail to build. Use the latest LTS version (currently 18.17.0) or the specific
|
to fail to build. Use the latest LTS version (currently 20.19.1 or the specific
|
||||||
version used by the main project to avoid this issue.
|
version used by the main project to avoid this issue.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Node.js comes with the Node Package Manager (npm) by default which can be used to
|
Node.js comes with the Node Package Manager (npm) by default which is used to
|
||||||
set up the project. The default package manager uses a fairly simplistic approach
|
set up the project.
|
||||||
to dependency resolution which can make builds take a long time. Yarn is an
|
|
||||||
alternative package manager which makes builds faster, especially for monolithic
|
|
||||||
projects like FreeSewing. If you'd like to install yarn run (`npm install yarn
|
|
||||||
-g`) (optional).
|
|
||||||
|
|
||||||
## Setting up the FreeSewing development environment
|
## Setting up the FreeSewing development environment
|
||||||
|
|
||||||
In VSCode or in a terminal, navigate to the folder you wish to contain your new patterns (e.g. `D:\Documents\my-freesewing-patterns`). Inside this directory run `npx @freesewing/new-design`.
|
In VSCode or in a terminal, navigate to the folder you wish to contain your new patterns (e.g. `D:\Documents\my-freesewing-patterns`). Inside this directory run `npx @freesewing/studio`.
|
||||||
|
|
||||||
After you've answered [some questions](#questions), it will take a while to set everything up.
|
After you've answered [some questions](#questions), it will take a while to set everything up.
|
||||||
When it's done, you will have a new folder with the development environment inside.
|
When it's done, you will have a new folder with the development environment inside.
|
||||||
|
@ -192,14 +184,6 @@ This will become the name of your design. Stick to \[a-z] here to avoid problems
|
||||||
|
|
||||||
If you're not certain what to pick, just mash some keys, it doesn't matter.
|
If you're not certain what to pick, just mash some keys, it doesn't matter.
|
||||||
|
|
||||||
#### What package manager to use
|
|
||||||
|
|
||||||
You may wish to choose `yarn` since that is the package manager
|
|
||||||
that we use when doing work in the monorepo,
|
|
||||||
and many of our tutorials are written to use `yarn`.
|
|
||||||
However, it doesn't really matter.
|
|
||||||
You can choose either `yarn` or `npm` as you wish.
|
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Start the development environment
|
## Start the development environment
|
||||||
|
@ -211,7 +195,7 @@ If you chose `banana`, you'll have a folder named `banana`.
|
||||||
You can ignore all other subfolders and files; they are part of the development environment.)
|
You can ignore all other subfolders and files; they are part of the development environment.)
|
||||||
|
|
||||||
To start the development environment, navigate to the folder that was created
|
To start the development environment, navigate to the folder that was created
|
||||||
and run `yarn dev` (or `npm run dev` if you're using npm as a package manager).
|
and run `npm run org`.
|
||||||
|
|
||||||
Then open your browser and go to http://localhost:8000
|
Then open your browser and go to http://localhost:8000
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,22 @@
|
||||||
---
|
---
|
||||||
title: Setting up the development environment
|
title: Setting up the FreeSewing development environment
|
||||||
sidebar_position: 20
|
sidebar_position: 20
|
||||||
---
|
---
|
||||||
|
|
||||||
FreeSewing provides a development environment that visualizes your design for
|
FreeSewing provides the studio, a development environment that visualizes your design for
|
||||||
you. This tutorial is for the stand-alone development environment, not the
|
you. This tutorial is for the stand-alone studio, not the
|
||||||
monorepo development environment (which you may have set up if you followed a
|
repository studio (which you may have set up if you followed a
|
||||||
getting started tutorial).
|
getting started tutorial).
|
||||||
|
|
||||||
To set it up, I will open a terminal and enter the following command:
|
To set it up, I will open a terminal and enter the following command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npx @freesewing/new-design
|
npx @freesewing/studio
|
||||||
```
|
```
|
||||||
|
|
||||||
It will ask if it is ok to install the development environment in a new folder
|
After you enter the folder name to create, it will take a while to set
|
||||||
named `freesewing`. You can accept the default, or pick a different folder name
|
everything up. When it's done, you will have a new folder with the development
|
||||||
if you prefer.
|
environment inside.
|
||||||
|
|
||||||
It will also ask what package manager you would like to use.
|
|
||||||
Here too the default (`npm`) is fine., unless you are certain you have **yarn** installed.
|
|
||||||
|
|
||||||
After answering these questions, files will be downloaded, dependencies installed,
|
|
||||||
and it will also initialize a git repository for you (if you have git on your system).
|
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
|
@ -31,29 +25,58 @@ of dependencies that need to be downloaded.
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
When it's ready, you can enter the `freesewing` directory that was just created and run `npm run dev`:
|
You will have a new folder that contains the stand-alone studio development environment.
|
||||||
|
(Within this new folder, the `design` subfolder holds your design's configuration files and source code.
|
||||||
|
You can ignore all other subfolders and files; they are part of the development environment.)
|
||||||
|
|
||||||
```sh
|
### Creating a new design
|
||||||
cd freesewing
|
|
||||||
npm run dev
|
If you would like to create a new design, enter the folder that was just
|
||||||
|
created and run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run add
|
||||||
```
|
```
|
||||||
|
|
||||||
Or if you want to use yarn as package manager:
|
After you've answered [some questions](#questions), it create a new
|
||||||
|
sub-folder for your design in the `designs` folder.
|
||||||
|
|
||||||
```sh
|
:::note
|
||||||
cd freesewing
|
|
||||||
yarn dev
|
### Questions
|
||||||
|
|
||||||
|
#### What design name to use
|
||||||
|
|
||||||
|
Please stick to a single word name using \[a-z] to avoid problems.
|
||||||
|
|
||||||
|
#### What template to use
|
||||||
|
|
||||||
|
Use `From scratch` unless you want to start from our of our blocks:
|
||||||
|
|
||||||
|
- Use `Extend Brian` to start from [Brian](https://freesewing.eu/designs/brian)
|
||||||
|
- Use `Extend Bent` to start from [Bent](https://freesewing.eu/designs/bent)
|
||||||
|
- Use `Extend Bella` to start from [Bella](https://freesewing.eu/designs/bella)
|
||||||
|
- Use `Extend Breanna` to start from [Breanna](https://freesewing.eu/designs/breanna)
|
||||||
|
- Use `Extend Titan` to start from [Titan](https://freesewing.eu/designs/titan)
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
### Starting the development environment
|
||||||
|
|
||||||
|
To start the development environment, enter the folder containing the
|
||||||
|
stand-alone studio and run `npm run start`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
Now open a browser and go to http://localhost:8000
|
Then open your browser and go to http://localhost:3000
|
||||||
|
|
||||||
If all goes well, we'll should see this landing page:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
|
The development environment will watch for any changes you make to
|
||||||
##### More detailed setup tutorials are available
|
the pattern's source code or configuration.
|
||||||
|
When you do, the pattern will update automatically in your browser.
|
||||||
|
:::
|
||||||
|
|
||||||
This pattern design tutorial contains only an abbreviated overview
|
This pattern design tutorial contains only an abbreviated overview
|
||||||
of the setup process.
|
of the setup process.
|
||||||
|
@ -69,7 +92,7 @@ For more detailed instructions, please refer to one of our setup tutorials:
|
||||||
|
|
||||||
##### Need help?
|
##### Need help?
|
||||||
|
|
||||||
If you run into any issues, head over to [FreeSewing.org/support](https://next.freesewing.org/support)
|
If you run into any issues, head over to [FreeSewing.eu/support](https://freesewing.eu/support)
|
||||||
which lists the various ways in which you can get help.
|
which lists the various ways in which you can get help.
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
|
@ -25,7 +25,7 @@ If you don't have NodeJS on your system, you can go to
|
||||||
|
|
||||||
##### NodeJS versions
|
##### NodeJS versions
|
||||||
|
|
||||||
You need Node.js 18 (lts/hydrogen) or higher to use FreeSewing
|
You need Node.js 20 (lts/iron) or higher to use FreeSewing
|
||||||
|
|
||||||
If you're looking to use different versions, I can recommend using `nvm` which makes this very easy: https://github.com/nvm-sh/nvm
|
If you're looking to use different versions, I can recommend using `nvm` which makes this very easy: https://github.com/nvm-sh/nvm
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
title: "Part 1: Prerequisites"
|
title: 'Part 1: Prerequisites'
|
||||||
---
|
---
|
||||||
|
|
||||||
In this first part, I will get your up and running with the FreeSewing
|
In this first part, I will get your up and running with the FreeSewing
|
||||||
|
@ -25,9 +25,20 @@ If you have NodeJS on your system, getting that development environment up
|
||||||
and running takes only a single command:
|
and running takes only a single command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npx @freesewing/new-design
|
npx @freesewing/studio
|
||||||
```
|
```
|
||||||
|
|
||||||
If you don't have NodeJS on your system --- or if you're not sure what
|
If you don't have NodeJS on your system --- or if you're not sure what
|
||||||
NodeJS is to begin with --- read on to learn how to install it.
|
NodeJS is to begin with --- read on to learn how to install it.
|
||||||
|
|
||||||
|
:::danger[Windows users also need to install `git`]
|
||||||
|
|
||||||
|
The `git` command line utility is also a requirement for installing the
|
||||||
|
FreeSewing development environment. Linux and Mac systems come with
|
||||||
|
`git` pre-installed, but Windows users will need to install it manually.
|
||||||
|
|
||||||
|
Please see the
|
||||||
|
[Getting started on Windows](/tutorials/getting-started-windows/)
|
||||||
|
tutorial for instructions on how to install `git` on a Windows system.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: The FreeSewing development environment
|
||||||
sidebar_position: 30
|
sidebar_position: 30
|
||||||
---
|
---
|
||||||
|
|
||||||
If you have been to FreeSewing.org the FreeSewing development environment will look familiar.
|
If you have been to FreeSewing.eu the FreeSewing development environment will look familiar.
|
||||||
That's because under the hood, it re-uses the same building blocks.
|
That's because under the hood, it re-uses the same building blocks.
|
||||||
|
|
||||||
At the top of the page is the header with a row of icons that lay out what is available to you.
|
At the top of the page is the header with a row of icons that lay out what is available to you.
|
||||||
|
|
|
@ -60,6 +60,7 @@ function draftBib({
|
||||||
tweak _ measurements.head / 12
|
tweak _ measurements.head / 12
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
points.rightCp1 = points.right.shift(
|
points.rightCp1 = points.right.shift(
|
||||||
90,
|
90,
|
||||||
points.bottom.dy(points.right) / 2
|
points.bottom.dy(points.right) / 2
|
||||||
|
@ -79,8 +80,8 @@ function draftBib({
|
||||||
.hide()
|
.hide()
|
||||||
|
|
||||||
delta = paths.quarterNeck.length() - target
|
delta = paths.quarterNeck.length() - target
|
||||||
if (delta > 0) tweak = tweak _ 0.99
|
if (delta > 0) tweak = tweak * 0.99
|
||||||
else tweak = tweak _ 1.02
|
else tweak = tweak * 1.02
|
||||||
|
|
||||||
} while (Math.abs(delta) > 1)
|
} while (Math.abs(delta) > 1)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ the JavaScript ecosystem, I can summarize that entire section in this one-liner
|
||||||
that sets up the FreeSewing development environment on your system:
|
that sets up the FreeSewing development environment on your system:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npx @freesewing/new-design
|
npx @freesewing/studio
|
||||||
```
|
```
|
||||||
|
|
||||||
## Part 2: Parametric design
|
## Part 2: Parametric design
|
||||||
|
@ -39,10 +39,9 @@ There is more to FreeSewing patterns than meets the eye, and in [Part
|
||||||
further value to your designs.
|
further value to your designs.
|
||||||
|
|
||||||
This includes things like translation, supporting laser cutters, avoiding the
|
This includes things like translation, supporting laser cutters, avoiding the
|
||||||
need to printing with so-called *paperless patterns*, as well as how you can
|
need to printing with so-called _paperless patterns_, as well as how you can
|
||||||
configure your pattern to integrate with FreeSewing.org, or your own
|
configure your pattern to integrate with FreeSewing.org, or your own
|
||||||
frontend.
|
frontend.
|
||||||
|
|
||||||
|
|
||||||
You can follow this tutorial start to finish, or skip ahead and back, the
|
You can follow this tutorial start to finish, or skip ahead and back, the
|
||||||
choice is yours.
|
choice is yours.
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Tabs from '@theme/Tabs'
|
||||||
import TabItem from '@theme/TabItem'
|
import TabItem from '@theme/TabItem'
|
||||||
import { pluginFlip } from '@freesewing/plugin-flip'
|
import { pluginFlip } from '@freesewing/plugin-flip'
|
||||||
import { pluginGore } from '@freesewing/plugin-gore'
|
import { pluginGore } from '@freesewing/plugin-gore'
|
||||||
|
import { pluginPathUtils } from '@freesewing/plugin-path-utils'
|
||||||
import { pluginRingsector } from '@freesewing/plugin-ringsector'
|
import { pluginRingsector } from '@freesewing/plugin-ringsector'
|
||||||
import { Design } from '@freesewing/core'
|
import { Design } from '@freesewing/core'
|
||||||
import yaml from 'js-yaml'
|
import yaml from 'js-yaml'
|
||||||
|
@ -49,7 +50,7 @@ const buildPattern = (children, settings = { margin: 5 }, tutorial = false, pape
|
||||||
lengthRatio: { pct: 75, min: 55, max: 85, menu: 'style' },
|
lengthRatio: { pct: 75, min: 55, max: 85, menu: 'style' },
|
||||||
}
|
}
|
||||||
: {},
|
: {},
|
||||||
plugins: [pluginFlip, pluginGore, pluginRingsector],
|
plugins: [pluginFlip, pluginGore, pluginPathUtils, pluginRingsector],
|
||||||
}
|
}
|
||||||
const design = new Design({
|
const design = new Design({
|
||||||
parts: [part],
|
parts: [part],
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="1000.0001"
|
||||||
|
height="570"
|
||||||
|
viewBox="0 0 264.58335 150.8125"
|
||||||
|
version="1.1"
|
||||||
|
id="svg562"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
|
sodipodi:docname="collarease.svg">
|
||||||
|
<defs
|
||||||
|
id="defs556">
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="Arrow1MstartQR"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||||
|
style="fill:#ff5b77;fill-rule:evenodd;stroke:#ff5b77;stroke-width:1.00000003pt;marker-start:none"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||||
|
id="path5084" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend3"
|
||||||
|
style="overflow:visible">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5087"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||||
|
style="fill:#ff5b77;fill-rule:evenodd;stroke:#ff5b77;stroke-width:1.00000003pt;marker-start:none"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker53"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||||
|
style="fill:#ff5b77;fill-rule:evenodd;stroke:#ff5b77;stroke-width:1.00000003pt;marker-start:none"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||||
|
id="path51" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="marker57"
|
||||||
|
style="overflow:visible">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path55"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||||
|
style="fill:#ff5b77;fill-rule:evenodd;stroke:#ff5b77;stroke-width:1.00000003pt;marker-start:none"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.8101934"
|
||||||
|
inkscape:cx="643.91418"
|
||||||
|
inkscape:cy="184.47717"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1043"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata559">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-47.625)">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccc"
|
||||||
|
style="fill:#808080;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="M 54.1423,55.951664 41.911976,57.89133 41.479965,72.528929 88.376337,70.286566 90.362996,57.874273 78.243784,55.951664 c -2.227828,2.394111 -6.970559,2.235652 -12.047084,2.235652 -5.836933,0.03682 -9.857971,0.124718 -12.0544,-2.235652 z"
|
||||||
|
id="inside"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="primary1"
|
||||||
|
style="fill:#404040;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 54.365069,55.951664 -24.994326,3.963971 c 0.172338,1.737552 3.199375,16.991043 3.199375,24.085049 0.437121,18.491896 -1.180108,20.477076 -2.081846,24.079736 2.059602,15.42627 -0.19137,23.36576 -0.19859,37.43095 0,15.45988 -2.473168,37.24966 -2.818075,41.08324 l 77.888383,0.1366 c -0.34465,-3.83357 -1.77452,-24.63877 -1.77452,-40.09865 0,-21.75303 -1.51285,-35.46062 -1.51285,-40.89932 -2.227137,-3.85782 -3.165523,-15.233969 -2.405677,-24.110942 0,-7.094007 3.614267,-19.969111 3.786587,-21.706663 L 78.466544,55.951664 C 76.238715,58.345775 79.8041,67.655702 66.41946,67.700859 53.034819,67.746011 56.561498,58.312034 54.365069,55.951664 Z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccsccccsc" />
|
||||||
|
<path
|
||||||
|
id="primary2"
|
||||||
|
style="fill:#404040;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 29.976678,59.796959 c 4.038677,5.842073 7.195097,34.945535 2.259218,43.712951 -3.300515,29.05614 -11.777082,63.63539 -14.767163,87.13685 -7.17153,0.38249 -9.8107924,0.34584 -14.4503455,-1.16564 C 3.325709,152.0588 11.092508,115.43576 19.69795,80.932692 22.337969,70.842832 26.664555,59.796959 29.976678,59.796959 Z m 73.645182,0 c -4.038678,5.842073 -7.195093,34.945535 -2.25922,43.712951 3.30052,29.05614 11.77708,63.63539 14.76716,87.13685 7.17153,0.38249 9.8108,0.34584 14.45035,-1.16564 -0.30732,-37.42232 -8.07412,-74.04536 -16.67956,-108.548428 -2.64002,-10.08986 -6.96661,-21.135733 -10.27873,-21.135733 z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path973"
|
||||||
|
d="m 182.5973,56.623458 -9.28477,1.267872 -0.43201,14.637599 46.89637,-2.242363 1.98666,-12.412293 -8.70857,-1.560874 c -2.22783,2.394111 -10.3812,1.873917 -15.45772,1.873917 -5.83694,0.03682 -12.80353,0.796512 -14.99996,-1.563858 z"
|
||||||
|
style="fill:#808080;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccsccccsc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 182.35499,56.623458 -21.58369,3.292177 c 0.17234,1.737552 3.19938,16.991043 3.19938,24.085049 0.43712,18.491896 -1.18011,20.477076 -2.08185,24.079736 2.0596,15.42627 -0.19137,23.36576 -0.19859,37.43095 0,15.45988 -2.47317,37.24966 -2.81808,41.08324 l 77.88839,0.1366 c -0.34465,-3.83357 -1.77452,-24.63877 -1.77452,-40.09865 0,-21.75303 -1.51285,-35.46062 -1.51285,-40.89932 -2.22714,-3.85782 -3.16553,-15.233969 -2.40568,-24.110942 0,-7.094007 3.61427,-19.969111 3.78659,-21.706663 l -22.04143,-3.600996 c -2.22783,2.394111 -1.608,12.997189 -14.99264,13.042346 -13.38464,0.04515 -13.2686,-10.373157 -15.46503,-12.733527 z"
|
||||||
|
style="fill:#404040;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="path975" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 161.37724,59.796959 c 4.03867,5.842073 7.19509,34.945535 2.25921,43.712951 -3.30051,29.05614 -11.77708,63.63539 -14.76716,87.13685 -7.17153,0.38249 -9.81079,0.34584 -14.45034,-1.16564 0.30732,-37.42232 8.07412,-74.04536 16.67956,-108.548428 2.64002,-10.08986 6.9666,-21.135733 10.27873,-21.135733 z m 73.64518,0 c -4.03868,5.842073 -7.1951,34.945535 -2.25922,43.712951 3.30052,29.05614 11.77708,63.63539 14.76716,87.13685 7.17153,0.38249 9.8108,0.34584 14.45035,-1.16564 -0.30732,-37.42232 -8.07412,-74.04536 -16.67956,-108.548428 -2.64002,-10.08986 -6.96661,-21.135733 -10.27873,-21.135733 z"
|
||||||
|
style="fill:#404040;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="path977" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.8 KiB |
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
title: 'Collar ease'
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Controls the amount of ease at your collar/neck and the size
|
||||||
|
of the neck opening..
|
||||||
|
|
||||||
|
Hugo uses the neck circumference measurement rather than head
|
||||||
|
circumference to produce the neck opening size when generating patterns.
|
||||||
|
Use this option to adjust the neck opening size if needed.
|
|
@ -10,6 +10,7 @@ import Armholedepth from '@site/docs/docs/designs/hugo/options/armholedepth/read
|
||||||
import Backneckcutout from '@site/docs/docs/designs/hugo/options/backneckcutout/readme.mdx'
|
import Backneckcutout from '@site/docs/docs/designs/hugo/options/backneckcutout/readme.mdx'
|
||||||
import Bicepsease from '@site/docs/docs/designs/hugo/options/bicepsease/readme.mdx'
|
import Bicepsease from '@site/docs/docs/designs/hugo/options/bicepsease/readme.mdx'
|
||||||
import Chestease from '@site/docs/docs/designs/hugo/options/chestease/readme.mdx'
|
import Chestease from '@site/docs/docs/designs/hugo/options/chestease/readme.mdx'
|
||||||
|
import Collarease from '@site/docs/docs/designs/hugo/options/collarease/readme.mdx'
|
||||||
import Cuffease from '@site/docs/docs/designs/hugo/options/cuffease/readme.mdx'
|
import Cuffease from '@site/docs/docs/designs/hugo/options/cuffease/readme.mdx'
|
||||||
import Draftforhighbust from '@site/docs/docs/designs/hugo/options/draftforhighbust/readme.mdx'
|
import Draftforhighbust from '@site/docs/docs/designs/hugo/options/draftforhighbust/readme.mdx'
|
||||||
import Hipsease from '@site/docs/docs/designs/hugo/options/hipsease/readme.mdx'
|
import Hipsease from '@site/docs/docs/designs/hugo/options/hipsease/readme.mdx'
|
||||||
|
@ -52,6 +53,16 @@ import Sleevelengthbonus from '@site/docs/docs/designs/hugo/options/sleevelength
|
||||||
|
|
||||||
<Chestease />
|
<Chestease />
|
||||||
|
|
||||||
|
### Collar ease {#collarease}
|
||||||
|
|
||||||
|
**The amount of ease around your neck**
|
||||||
|
- Type: **Percentage**
|
||||||
|
- Default: **15%**
|
||||||
|
- Minimum: **0%**
|
||||||
|
- Maximum: **40%**
|
||||||
|
|
||||||
|
<Collarease />
|
||||||
|
|
||||||
### Cuff ease {#cuffease}
|
### Cuff ease {#cuffease}
|
||||||
|
|
||||||
**The amount of ease at your wrist.**
|
**The amount of ease at your wrist.**
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: 'Legacy waist and hips calculations'
|
||||||
|
---
|
||||||
|
|
||||||
|
This option allows you to use the legacy way of calculating the waist
|
||||||
|
and hips.
|
||||||
|
|
||||||
|
The legacy (v3) way used the chest circumference to set the intial waist
|
||||||
|
and hips points.
|
||||||
|
It then used waist and hips measurements to attempt to move the waist
|
||||||
|
and hips points towards the actual measurement values.
|
||||||
|
|
||||||
|
The new, v4 way instead uses the actual waist and hips measurements to
|
||||||
|
set the waist and hips points.
|
||||||
|
It also contains corrections to the front waist dart and side seam
|
||||||
|
adjustments to maintain the correct width and ease at the waist and hips.
|
||||||
|
It also adjusts the armhole point after the dart rotation to maintain
|
||||||
|
the correct width and ease at the armhole.
|
||||||
|
|
||||||
|
If you enable this option, Wahid will revert to the v3 way of calculating
|
||||||
|
waist and hips points.
|
|
@ -21,6 +21,7 @@ import Hemradius from '@site/docs/docs/designs/wahid/options/hemradius/readme.md
|
||||||
import Hemstyle from '@site/docs/docs/designs/wahid/options/hemstyle/readme.mdx'
|
import Hemstyle from '@site/docs/docs/designs/wahid/options/hemstyle/readme.mdx'
|
||||||
import Hipsease from '@site/docs/docs/designs/wahid/options/hipsease/readme.mdx'
|
import Hipsease from '@site/docs/docs/designs/wahid/options/hipsease/readme.mdx'
|
||||||
import Legacyarmholedepth from '@site/docs/docs/designs/wahid/options/legacyarmholedepth/readme.mdx'
|
import Legacyarmholedepth from '@site/docs/docs/designs/wahid/options/legacyarmholedepth/readme.mdx'
|
||||||
|
import Legacywaisthips from '@site/docs/docs/designs/wahid/options/legacywaisthips/readme.mdx'
|
||||||
import Lengthbonus from '@site/docs/docs/designs/wahid/options/lengthbonus/readme.mdx'
|
import Lengthbonus from '@site/docs/docs/designs/wahid/options/lengthbonus/readme.mdx'
|
||||||
import Neckinset from '@site/docs/docs/designs/wahid/options/neckinset/readme.mdx'
|
import Neckinset from '@site/docs/docs/designs/wahid/options/neckinset/readme.mdx'
|
||||||
import Necklinedrop from '@site/docs/docs/designs/wahid/options/necklinedrop/readme.mdx'
|
import Necklinedrop from '@site/docs/docs/designs/wahid/options/necklinedrop/readme.mdx'
|
||||||
|
@ -255,6 +256,14 @@ import Weltheight from '@site/docs/docs/designs/wahid/options/weltheight/readme.
|
||||||
|
|
||||||
<Legacyarmholedepth />
|
<Legacyarmholedepth />
|
||||||
|
|
||||||
|
### Legacy waist and hips widths {#legacywaisthips}
|
||||||
|
|
||||||
|
**Enable this option to use the legacy (v3) way to calculate the waist and hips widths (using chest circumference) rather than the new way (using the waist and hips measurements).**
|
||||||
|
- Type: **Boolean**
|
||||||
|
- Default: **false**
|
||||||
|
|
||||||
|
<Legacywaisthips />
|
||||||
|
|
||||||
### Neck inset {#neckinset}
|
### Neck inset {#neckinset}
|
||||||
|
|
||||||
**How much the shoulder seam is cut inwards at the neck**
|
**How much the shoulder seam is cut inwards at the neck**
|
||||||
|
|
|
@ -25,6 +25,22 @@ function customizeSidebar(items) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter out submenus in Your Measurements Sets and Your Patterns
|
||||||
|
for (const item in items) {
|
||||||
|
if (items[item].label === 'Account') {
|
||||||
|
for (const design in items[item].items) {
|
||||||
|
for (const subpage in items[item].items[design].items) {
|
||||||
|
if (
|
||||||
|
items[item].items[design].items[subpage].label === 'Your Measurements Sets' ||
|
||||||
|
items[item].items[design].items[subpage].label === 'Your Patterns'
|
||||||
|
) {
|
||||||
|
items[item].items[design].items[subpage].items = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="1000.0001"
|
||||||
|
height="570"
|
||||||
|
viewBox="0 0 264.58335 150.8125"
|
||||||
|
version="1.1"
|
||||||
|
id="svg562"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
|
sodipodi:docname="collarease.svg">
|
||||||
|
<defs
|
||||||
|
id="defs556">
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="Arrow1MstartQR"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||||
|
style="fill:#ff5b77;fill-rule:evenodd;stroke:#ff5b77;stroke-width:1.00000003pt;marker-start:none"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||||
|
id="path5084" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend3"
|
||||||
|
style="overflow:visible">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5087"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||||
|
style="fill:#ff5b77;fill-rule:evenodd;stroke:#ff5b77;stroke-width:1.00000003pt;marker-start:none"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker53"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||||
|
style="fill:#ff5b77;fill-rule:evenodd;stroke:#ff5b77;stroke-width:1.00000003pt;marker-start:none"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||||
|
id="path51" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="marker57"
|
||||||
|
style="overflow:visible">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path55"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||||
|
style="fill:#ff5b77;fill-rule:evenodd;stroke:#ff5b77;stroke-width:1.00000003pt;marker-start:none"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.8101934"
|
||||||
|
inkscape:cx="643.91418"
|
||||||
|
inkscape:cy="184.47717"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1043"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata559">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-47.625)">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccc"
|
||||||
|
style="fill:#808080;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="M 54.1423,55.951664 41.911976,57.89133 41.479965,72.528929 88.376337,70.286566 90.362996,57.874273 78.243784,55.951664 c -2.227828,2.394111 -6.970559,2.235652 -12.047084,2.235652 -5.836933,0.03682 -9.857971,0.124718 -12.0544,-2.235652 z"
|
||||||
|
id="inside"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="primary1"
|
||||||
|
style="fill:#404040;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 54.365069,55.951664 -24.994326,3.963971 c 0.172338,1.737552 3.199375,16.991043 3.199375,24.085049 0.437121,18.491896 -1.180108,20.477076 -2.081846,24.079736 2.059602,15.42627 -0.19137,23.36576 -0.19859,37.43095 0,15.45988 -2.473168,37.24966 -2.818075,41.08324 l 77.888383,0.1366 c -0.34465,-3.83357 -1.77452,-24.63877 -1.77452,-40.09865 0,-21.75303 -1.51285,-35.46062 -1.51285,-40.89932 -2.227137,-3.85782 -3.165523,-15.233969 -2.405677,-24.110942 0,-7.094007 3.614267,-19.969111 3.786587,-21.706663 L 78.466544,55.951664 C 76.238715,58.345775 79.8041,67.655702 66.41946,67.700859 53.034819,67.746011 56.561498,58.312034 54.365069,55.951664 Z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccsccccsc" />
|
||||||
|
<path
|
||||||
|
id="primary2"
|
||||||
|
style="fill:#404040;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 29.976678,59.796959 c 4.038677,5.842073 7.195097,34.945535 2.259218,43.712951 -3.300515,29.05614 -11.777082,63.63539 -14.767163,87.13685 -7.17153,0.38249 -9.8107924,0.34584 -14.4503455,-1.16564 C 3.325709,152.0588 11.092508,115.43576 19.69795,80.932692 22.337969,70.842832 26.664555,59.796959 29.976678,59.796959 Z m 73.645182,0 c -4.038678,5.842073 -7.195093,34.945535 -2.25922,43.712951 3.30052,29.05614 11.77708,63.63539 14.76716,87.13685 7.17153,0.38249 9.8108,0.34584 14.45035,-1.16564 -0.30732,-37.42232 -8.07412,-74.04536 -16.67956,-108.548428 -2.64002,-10.08986 -6.96661,-21.135733 -10.27873,-21.135733 z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path973"
|
||||||
|
d="m 182.5973,56.623458 -9.28477,1.267872 -0.43201,14.637599 46.89637,-2.242363 1.98666,-12.412293 -8.70857,-1.560874 c -2.22783,2.394111 -10.3812,1.873917 -15.45772,1.873917 -5.83694,0.03682 -12.80353,0.796512 -14.99996,-1.563858 z"
|
||||||
|
style="fill:#808080;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccsccccsc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 182.35499,56.623458 -21.58369,3.292177 c 0.17234,1.737552 3.19938,16.991043 3.19938,24.085049 0.43712,18.491896 -1.18011,20.477076 -2.08185,24.079736 2.0596,15.42627 -0.19137,23.36576 -0.19859,37.43095 0,15.45988 -2.47317,37.24966 -2.81808,41.08324 l 77.88839,0.1366 c -0.34465,-3.83357 -1.77452,-24.63877 -1.77452,-40.09865 0,-21.75303 -1.51285,-35.46062 -1.51285,-40.89932 -2.22714,-3.85782 -3.16553,-15.233969 -2.40568,-24.110942 0,-7.094007 3.61427,-19.969111 3.78659,-21.706663 l -22.04143,-3.600996 c -2.22783,2.394111 -1.608,12.997189 -14.99264,13.042346 -13.38464,0.04515 -13.2686,-10.373157 -15.46503,-12.733527 z"
|
||||||
|
style="fill:#404040;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="path975" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 161.37724,59.796959 c 4.03867,5.842073 7.19509,34.945535 2.25921,43.712951 -3.30051,29.05614 -11.77708,63.63539 -14.76716,87.13685 -7.17153,0.38249 -9.81079,0.34584 -14.45034,-1.16564 0.30732,-37.42232 8.07412,-74.04536 16.67956,-108.548428 2.64002,-10.08986 6.9666,-21.135733 10.27873,-21.135733 z m 73.64518,0 c -4.03868,5.842073 -7.1951,34.945535 -2.25922,43.712951 3.30052,29.05614 11.77708,63.63539 14.76716,87.13685 7.17153,0.38249 9.8108,0.34584 14.45035,-1.16564 -0.30732,-37.42232 -8.07412,-74.04536 -16.67956,-108.548428 -2.64002,-10.08986 -6.96661,-21.135733 -10.27873,-21.135733 z"
|
||||||
|
style="fill:#404040;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="path977" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.8 KiB |
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
title: 'Collar ease'
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Controls the amount of ease at your collar/neck and the size
|
||||||
|
of the neck opening..
|
||||||
|
|
||||||
|
Hugo uses the neck circumference measurement rather than head
|
||||||
|
circumference to produce the neck opening size when generating patterns.
|
||||||
|
Use this option to adjust the neck opening size if needed.
|
|
@ -2,6 +2,25 @@ import { themes as prismThemes } from 'prism-react-renderer'
|
||||||
import { docusaurusPlugins } from './plugins/index.mjs'
|
import { docusaurusPlugins } from './plugins/index.mjs'
|
||||||
import smartypants from 'remark-smartypants'
|
import smartypants from 'remark-smartypants'
|
||||||
|
|
||||||
|
function customizeSidebar(items) {
|
||||||
|
// Filter out submenus in Your Measurements Sets and Your Patterns
|
||||||
|
for (const item in items) {
|
||||||
|
if (items[item].label === 'Account') {
|
||||||
|
for (const design in items[item].items) {
|
||||||
|
for (const subpage in items[item].items[design].items) {
|
||||||
|
if (
|
||||||
|
items[item].items[design].items[subpage].label === 'Your Measurements Sets' ||
|
||||||
|
items[item].items[design].items[subpage].label === 'Your Patterns'
|
||||||
|
) {
|
||||||
|
items[item].items[design].items[subpage].items = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
title: 'FreeSewing Studio',
|
title: 'FreeSewing Studio',
|
||||||
tagline: 'FreeSewing for Designers',
|
tagline: 'FreeSewing for Designers',
|
||||||
|
@ -25,6 +44,10 @@ const config = {
|
||||||
docs: {
|
docs: {
|
||||||
routeBasePath: '/',
|
routeBasePath: '/',
|
||||||
sidebarPath: './sidebars.js',
|
sidebarPath: './sidebars.js',
|
||||||
|
async sidebarItemsGenerator({ defaultSidebarItemsGenerator, ...args }) {
|
||||||
|
const sidebarItems = await defaultSidebarItemsGenerator(args)
|
||||||
|
return customizeSidebar(sidebarItems)
|
||||||
|
},
|
||||||
remarkPlugins: [[smartypants, { dashes: 'oldschool' }]],
|
remarkPlugins: [[smartypants, { dashes: 'oldschool' }]],
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue