commit
be24625373
75 changed files with 5833 additions and 851 deletions
|
@ -1,5 +1,17 @@
|
||||||
Unreleased:
|
Unreleased:
|
||||||
|
|
||||||
Added:
|
Added:
|
||||||
|
plugin-annotations:
|
||||||
|
- The `title` macro now takes a `notes` and `classes.notes` as its config, allowing you to add notes
|
||||||
|
- The `classes.cutlist` config is removed from the title plugin, cutlist info is now included as notes
|
||||||
|
plugin-i18n:
|
||||||
|
- This plugin now supports translation of nested arrays of strings, giving you more flexibility to concatenate translated parts of strings
|
||||||
|
react-components:
|
||||||
|
- This Pattern component now supports translation of nested arrays of strings, giving you more flexibility to concatenate translated parts of strings
|
||||||
|
|
||||||
|
Removed:
|
||||||
|
plugin-annotations:
|
||||||
|
- The `classes.cutlist` config is removed from the title plugin, cutlist info is now included as notes
|
||||||
|
|
||||||
3.1.0:
|
3.1.0:
|
||||||
date: 2023-12-26
|
date: 2023-12-26
|
||||||
|
|
|
@ -88,11 +88,11 @@ jaeger:
|
||||||
'@freesewing/plugin-bust': *freesewing
|
'@freesewing/plugin-bust': *freesewing
|
||||||
new-design:
|
new-design:
|
||||||
_:
|
_:
|
||||||
'axios': &axios '1.6.2'
|
'axios': &axios '1.6.4'
|
||||||
'chalk': '5.3.0'
|
'chalk': '5.3.0'
|
||||||
'execa': '8.0.1'
|
'execa': '8.0.1'
|
||||||
'mustache': &mustache '4.2.0'
|
'mustache': &mustache '4.2.0'
|
||||||
'ora': &ora '7.0.1'
|
'ora': &ora '8.0.1'
|
||||||
'prompts': '2.4.2'
|
'prompts': '2.4.2'
|
||||||
'recursive-readdir': '2.2.3'
|
'recursive-readdir': '2.2.3'
|
||||||
noble:
|
noble:
|
||||||
|
@ -180,7 +180,7 @@ yuri:
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
_:
|
_:
|
||||||
'@aws-sdk/client-sesv2': '3.478.0'
|
'@aws-sdk/client-sesv2': '3.485.0'
|
||||||
'@prisma/client': &prisma '5.7.1'
|
'@prisma/client': &prisma '5.7.1'
|
||||||
'bcryptjs': '2.4.3'
|
'bcryptjs': '2.4.3'
|
||||||
'cors': '2.8.5'
|
'cors': '2.8.5'
|
||||||
|
@ -193,14 +193,14 @@ backend:
|
||||||
'passport': '0.7.0'
|
'passport': '0.7.0'
|
||||||
'passport-http': '0.3.0'
|
'passport-http': '0.3.0'
|
||||||
'passport-jwt': '4.0.1'
|
'passport-jwt': '4.0.1'
|
||||||
'pino': '8.17.1'
|
'pino': '8.17.2'
|
||||||
'qrcode': '1.5.3'
|
'qrcode': '1.5.3'
|
||||||
'swagger-ui-dist': '5.10.5'
|
'swagger-ui-dist': '5.10.5'
|
||||||
'swagger-ui-express': '5.0.0'
|
'swagger-ui-express': '5.0.0'
|
||||||
dev:
|
dev:
|
||||||
'chai': *chai
|
'chai': *chai
|
||||||
'chai-http': '4.4.0'
|
'chai-http': '4.4.0'
|
||||||
'esbuild': '0.19.10'
|
'esbuild': '0.19.11'
|
||||||
'mocha': *mocha
|
'mocha': *mocha
|
||||||
'mocha-steps': '1.3.0'
|
'mocha-steps': '1.3.0'
|
||||||
'nodemon': '3.0.2'
|
'nodemon': '3.0.2'
|
||||||
|
@ -214,7 +214,7 @@ dev:
|
||||||
'@next/bundle-analyzer': &next '14.0.4'
|
'@next/bundle-analyzer': &next '14.0.4'
|
||||||
'@tailwindcss/typography': &tailwindTypography '0.5.10'
|
'@tailwindcss/typography': &tailwindTypography '0.5.10'
|
||||||
'algoliasearch': '4.22.0'
|
'algoliasearch': '4.22.0'
|
||||||
'daisyui': &daisyui '4.4.23'
|
'daisyui': &daisyui '4.5.0'
|
||||||
'lodash.get': *_get
|
'lodash.get': *_get
|
||||||
'lodash.orderby': &_orderby '4.6.0'
|
'lodash.orderby': &_orderby '4.6.0'
|
||||||
'lodash.set': *_set
|
'lodash.set': *_set
|
||||||
|
@ -222,7 +222,7 @@ dev:
|
||||||
'react': &react '18.2.0'
|
'react': &react '18.2.0'
|
||||||
'react-copy-to-clipboard': &reactCopyToClipboard '5.1.0'
|
'react-copy-to-clipboard': &reactCopyToClipboard '5.1.0'
|
||||||
'react-dom': *react
|
'react-dom': *react
|
||||||
'react-hotkeys-hook': &reactHotkeysHook '4.4.1'
|
'react-hotkeys-hook': &reactHotkeysHook '4.4.3'
|
||||||
'react-instantsearch-dom': &reactInstantsearchDom '6.40.4'
|
'react-instantsearch-dom': &reactInstantsearchDom '6.40.4'
|
||||||
'react-instantsearch-hooks-web': '6.47.3'
|
'react-instantsearch-hooks-web': '6.47.3'
|
||||||
'react-swipeable': &reactSwipeable '7.0.1'
|
'react-swipeable': &reactSwipeable '7.0.1'
|
||||||
|
@ -240,7 +240,7 @@ dev:
|
||||||
dev: &nextSiteDevDependencies
|
dev: &nextSiteDevDependencies
|
||||||
'autoprefixer': &autoprefixer '10.4.16'
|
'autoprefixer': &autoprefixer '10.4.16'
|
||||||
'js-yaml': &jsYaml '4.1.0'
|
'js-yaml': &jsYaml '4.1.0'
|
||||||
'postcss': &postcss '8.4.32'
|
'postcss': &postcss '8.4.33'
|
||||||
'remark-extract-frontmatter': '3.2.0'
|
'remark-extract-frontmatter': '3.2.0'
|
||||||
'remark-mdx-frontmatter': &mdxfrontmatter '4.0.0'
|
'remark-mdx-frontmatter': &mdxfrontmatter '4.0.0'
|
||||||
'tailwindcss': &tailwindcss '3.4.0'
|
'tailwindcss': &tailwindcss '3.4.0'
|
||||||
|
@ -257,12 +257,12 @@ lab:
|
||||||
'd3-drag': &d3drag '3.0.0'
|
'd3-drag': &d3drag '3.0.0'
|
||||||
'd3-selection': &d3selection '3.0.0'
|
'd3-selection': &d3selection '3.0.0'
|
||||||
'daisyui': *daisyui
|
'daisyui': *daisyui
|
||||||
'i18next': &i18next '23.7.11'
|
'i18next': &i18next '23.7.15'
|
||||||
'lodash.get': *_get
|
'lodash.get': *_get
|
||||||
'lodash.orderby': *_orderby
|
'lodash.orderby': *_orderby
|
||||||
'lodash.set': *_set
|
'lodash.set': *_set
|
||||||
'next': *next
|
'next': *next
|
||||||
'next-i18next': &nextI18next '15.1.1'
|
'next-i18next': &nextI18next '15.2.0'
|
||||||
'ora': *ora
|
'ora': *ora
|
||||||
'react': *react
|
'react': *react
|
||||||
'react-copy-to-clipboard': *reactCopyToClipboard
|
'react-copy-to-clipboard': *reactCopyToClipboard
|
||||||
|
@ -284,7 +284,7 @@ lab:
|
||||||
|
|
||||||
org:
|
org:
|
||||||
_:
|
_:
|
||||||
'@bugsnag/js': &bugsnag 7.22.2
|
'@bugsnag/js': &bugsnag 7.22.3
|
||||||
'@bugsnag/plugin-react': 7.19.0
|
'@bugsnag/plugin-react': 7.19.0
|
||||||
'@mdx-js/mdx': *mdx
|
'@mdx-js/mdx': *mdx
|
||||||
'@mdx-js/react': *mdx
|
'@mdx-js/react': *mdx
|
||||||
|
@ -296,12 +296,12 @@ org:
|
||||||
'daisyui': *daisyui
|
'daisyui': *daisyui
|
||||||
'echarts': &echarts 5.4.3
|
'echarts': &echarts 5.4.3
|
||||||
'echarts-for-react': &echartsReact 3.0.2
|
'echarts-for-react': &echartsReact 3.0.2
|
||||||
'jotai': &jotai '2.6.0'
|
'jotai': &jotai '2.6.1'
|
||||||
'jotai-location': &jotai-location '0.5.2'
|
'jotai-location': &jotai-location '0.5.2'
|
||||||
'lodash.get': *_get
|
'lodash.get': *_get
|
||||||
'lodash.orderby': *_orderby
|
'lodash.orderby': *_orderby
|
||||||
'lodash.set': *_set
|
'lodash.set': *_set
|
||||||
'luxon': '3.4.3'
|
'luxon': '3.4.4'
|
||||||
'next': *next
|
'next': *next
|
||||||
'ora': *ora
|
'ora': *ora
|
||||||
'react-dropzone': &dropzone '14.2.3'
|
'react-dropzone': &dropzone '14.2.3'
|
||||||
|
@ -366,7 +366,7 @@ shared:
|
||||||
'to-vfile': '8.0.0'
|
'to-vfile': '8.0.0'
|
||||||
'unist-util-visit': *unist-util-visit
|
'unist-util-visit': *unist-util-visit
|
||||||
'use-local-storage-state': *use-local-storage-state
|
'use-local-storage-state': *use-local-storage-state
|
||||||
'web-worker': &webworker '1.2.0'
|
'web-worker': &webworker '1.3.0'
|
||||||
dev:
|
dev:
|
||||||
'recursive-readdir': '^2.2.3'
|
'recursive-readdir': '^2.2.3'
|
||||||
'html-to-text': '^9.0.5'
|
'html-to-text': '^9.0.5'
|
||||||
|
|
|
@ -519,6 +519,16 @@
|
||||||
],
|
],
|
||||||
"techniques": []
|
"techniques": []
|
||||||
},
|
},
|
||||||
|
"naomiwu": {
|
||||||
|
"description": "A FreeSewing pattern for Naomi Wu's signature cargo skirt",
|
||||||
|
"code": "Joost De Cock",
|
||||||
|
"design": ["Naomi Wu", "Joost De Cock"],
|
||||||
|
"difficulty": 3,
|
||||||
|
"lab": false,
|
||||||
|
"org": false,
|
||||||
|
"tags": ["bottoms", "skirts"],
|
||||||
|
"techniques": ["button", "hem", "pocket", "lining"]
|
||||||
|
},
|
||||||
"noble": {
|
"noble": {
|
||||||
"code": "Wouter Van Wageningen",
|
"code": "Wouter Van Wageningen",
|
||||||
"description": "A FreeSewing pattern for a princess seam bodice block",
|
"description": "A FreeSewing pattern for a princess seam bodice block",
|
||||||
|
|
17
designs/naomiwu/CHANGELOG.md
Normal file
17
designs/naomiwu/CHANGELOG.md
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Change log for: @freesewing/naomiwu
|
||||||
|
|
||||||
|
|
||||||
|
## 3.0.0 (2023-09-30)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- All FreeSewing pacakges are now ESM only.
|
||||||
|
- All FreeSewing pacakges now use named exports.
|
||||||
|
- Dropped support for NodeJS 14. NodeJS 18 (LTS/hydrogen) or more recent is now required.
|
||||||
|
|
||||||
|
|
||||||
|
This is the **initial release**, and the start of this change log.
|
||||||
|
|
||||||
|
> Prior to version 2, FreeSewing was not a JavaScript project.
|
||||||
|
> As such, that history is out of scope for this change log.
|
||||||
|
|
143
designs/naomiwu/README.md
Normal file
143
designs/naomiwu/README.md
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|

|
||||||
|
<p align='center'><a
|
||||||
|
href="https://www.npmjs.com/package/@freesewing/naomiwu"
|
||||||
|
title="@freesewing/naomiwu on NPM"
|
||||||
|
><img src="https://img.shields.io/npm/v/@freesewing/naomiwu.svg"
|
||||||
|
alt="@freesewing/naomiwu on NPM"/>
|
||||||
|
</a><a
|
||||||
|
href="https://opensource.org/licenses/MIT"
|
||||||
|
title="License: MIT"
|
||||||
|
><img src="https://img.shields.io/npm/l/@freesewing/naomiwu.svg?label=License"
|
||||||
|
alt="License: MIT"/>
|
||||||
|
</a><a
|
||||||
|
href="https://deepscan.io/dashboard#view=project&tid=2114&pid=2993&bid=23256"
|
||||||
|
title="Code quality on DeepScan"
|
||||||
|
><img src="https://deepscan.io/api/teams/2114/projects/2993/branches/23256/badge/grade.svg"
|
||||||
|
alt="Code quality on DeepScan"/>
|
||||||
|
</a><a
|
||||||
|
href="https://github.com/freesewing/freesewing/issues?q=is%3Aissue+is%3Aopen+label%3Apkg%3Anaomiwu"
|
||||||
|
title="Open issues tagged pkg:naomiwu"
|
||||||
|
><img src="https://img.shields.io/github/issues/freesewing/freesewing/pkg:naomiwu.svg?label=Issues"
|
||||||
|
alt="Open issues tagged pkg:naomiwu"/>
|
||||||
|
</a><a
|
||||||
|
href="#contributors-"
|
||||||
|
title="All Contributors"
|
||||||
|
><img src="https://img.shields.io/badge/all_contributors-119-pink.svg"
|
||||||
|
alt="All Contributors"/>
|
||||||
|
</a></p><p align='center'><a
|
||||||
|
href="https://twitter.com/freesewing_org"
|
||||||
|
title="Follow @freesewing_org on Twitter"
|
||||||
|
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Follow%20us-blue.svg?logo=twitter&logoColor=white&logoWidth=15"
|
||||||
|
alt="Follow @freesewing_org on Twitter"/>
|
||||||
|
</a><a
|
||||||
|
href="https://chat.freesewing.org"
|
||||||
|
title="Chat with us on Discord"
|
||||||
|
><img src="https://img.shields.io/discord/698854858052075530?label=Chat%20on%20Discord"
|
||||||
|
alt="Chat with us on Discord"/>
|
||||||
|
</a><a
|
||||||
|
href="https://freesewing.org/patrons/join"
|
||||||
|
title="Become a FreeSewing Patron"
|
||||||
|
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Support%20us-blueviolet.svg?logo=cash-app&logoColor=white&logoWidth=15"
|
||||||
|
alt="Become a FreeSewing Patron"/>
|
||||||
|
</a><a
|
||||||
|
href="https://instagram.com/freesewing_org"
|
||||||
|
title="Follow @freesewing_org on Twitter"
|
||||||
|
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Follow%20us-E4405F.svg?logo=instagram&logoColor=white&logoWidth=15"
|
||||||
|
alt="Follow @freesewing_org on Twitter"/>
|
||||||
|
</a></p>
|
||||||
|
|
||||||
|
# @freesewing/naomiwu
|
||||||
|
|
||||||
|
A FreeSewing pattern for Naomi Wu's signature cargo skirt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## What am I looking at? 🤔
|
||||||
|
|
||||||
|
This repository is the FreeSewing *monorepo* holding all FreeSewing's websites, documentation, designs, plugins, and other NPM packages.
|
||||||
|
|
||||||
|
This folder holds: @freesewing/naomiwu
|
||||||
|
|
||||||
|
If you're not entirely sure what to do or how to start, type this command:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run tips
|
||||||
|
```
|
||||||
|
|
||||||
|
> If you don't want to set up a dev environment, you can run it in your browser:
|
||||||
|
>
|
||||||
|
> [](https://gitpod.io/#https://github.com/freesewing/freesewing)
|
||||||
|
>
|
||||||
|
> We recommend that you fork our repository and then
|
||||||
|
> put `gitpod.io/#<entire-url-of-your-fork` into a browser
|
||||||
|
> to start up a browser-based dev environment of your own.
|
||||||
|
|
||||||
|
## About FreeSewing 💀
|
||||||
|
|
||||||
|
Where the world of makers and developers collide, that's where you'll find FreeSewing.
|
||||||
|
|
||||||
|
If you're a maker, checkout [freesewing.org](https://freesewing.org/) where you can generate
|
||||||
|
sewing patterns adapted to your measurements.
|
||||||
|
|
||||||
|
If you're a developer, the FreeSewing documentation lives at [freesewing.dev](https://freesewing.dev/).
|
||||||
|
The FreeSewing [core library](https://freesewing.dev/reference/api/) is a *batteries-included* toolbox
|
||||||
|
for parametric design of sewing patterns. But FreeSewing also provides a range
|
||||||
|
of [plugins](https://freesewing.dev/reference/plugins/) that further extend the
|
||||||
|
functionality of the platform.
|
||||||
|
|
||||||
|
If you have NodeJS installed, you can try it right now by running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx create-freesewing-pattern
|
||||||
|
```
|
||||||
|
|
||||||
|
Getting started guides are available for:
|
||||||
|
- [Linux](https://freesewing.dev/tutorials/getting-started-linux/)
|
||||||
|
- [MacOS](https://freesewing.dev/tutorials/getting-started-mac/)
|
||||||
|
- [Windows](https://freesewing.dev/tutorials/getting-started-windows/)
|
||||||
|
|
||||||
|
The [pattern design tutorial](https://freesewing.dev/tutorials/pattern-design/) will
|
||||||
|
show you how to create your first parametric design.
|
||||||
|
|
||||||
|
## Support FreeSewing: Become a patron 🥰
|
||||||
|
|
||||||
|
FreeSewing is an open source project maintained by Joost De Cock and financially supported by the FreeSewing patrons.
|
||||||
|
|
||||||
|
If you feel FreeSewing is worthwhile, and you can spend a few coins without
|
||||||
|
hardship, then you should [join us and become a patron](https://freesewing.org/community/join).
|
||||||
|
|
||||||
|
## Links 👩💻
|
||||||
|
|
||||||
|
**Official channels**
|
||||||
|
|
||||||
|
- 💻 Makers website: [FreeSewing.org](https://freesewing.org)
|
||||||
|
- 💻 Developers website: [FreeSewing.dev](https://freesewing.dev)
|
||||||
|
- ✅ [Support](https://github.com/freesewing/freesewing/issues/new/choose),
|
||||||
|
[Issues](https://github.com/freesewing/freesewing/issues) &
|
||||||
|
[Discussions](https://github.com/freesewing/freesewing/discussions) on
|
||||||
|
[GitHub](https://github.com/freesewing/freesewing)
|
||||||
|
|
||||||
|
**Social media**
|
||||||
|
|
||||||
|
- 🐦 Twitter: [@freesewing_org](https://twitter.com/freesewing_org)
|
||||||
|
- 📷 Instagram: [@freesewing_org](https://instagram.com/freesewing_org)
|
||||||
|
|
||||||
|
**Places the FreeSewing community hangs out**
|
||||||
|
|
||||||
|
- 💬 [Discord](https://discord.freesewing.org/)
|
||||||
|
- 💬 [Facebook](https://www.facebook.com/groups/627769821272714/)
|
||||||
|
- 💬 [Reddit](https://www.reddit.com/r/freesewing/)
|
||||||
|
|
||||||
|
## License: MIT 🤓
|
||||||
|
|
||||||
|
© [Joost De Cock](https://github.com/joostdecock).
|
||||||
|
See [the license file](https://github.com/freesewing/freesewing/blob/develop/LICENSE) for details.
|
||||||
|
|
||||||
|
## Where to get help 🤯
|
||||||
|
|
||||||
|
For [Support](https://github.com/freesewing/freesewing/issues/new/choose),
|
||||||
|
please use the [Issues](https://github.com/freesewing/freesewing/issues) &
|
||||||
|
[Discussions](https://github.com/freesewing/freesewing/discussions) on
|
||||||
|
[GitHub](https://github.com/freesewing/freesewing).
|
||||||
|
|
35
designs/naomiwu/build.mjs
Normal file
35
designs/naomiwu/build.mjs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* This script will build the package with esbuild */
|
||||||
|
import esbuild from 'esbuild'
|
||||||
|
import pkg from './package.json' assert { type: 'json' }
|
||||||
|
|
||||||
|
// Create banner based on package info
|
||||||
|
const banner = `/**
|
||||||
|
* ${pkg.name} | v${pkg.version}
|
||||||
|
* ${pkg.description}
|
||||||
|
* (c) ${new Date().getFullYear()} ${pkg.author}
|
||||||
|
* @license ${pkg.license}
|
||||||
|
*/`
|
||||||
|
|
||||||
|
// Shared esbuild options
|
||||||
|
const options = {
|
||||||
|
banner: { js: banner },
|
||||||
|
bundle: true,
|
||||||
|
entryPoints: ['src/index.mjs'],
|
||||||
|
format: 'esm',
|
||||||
|
outfile: 'dist/index.mjs',
|
||||||
|
external: ['@freesewing'],
|
||||||
|
metafile: process.env.VERBOSE ? true : false,
|
||||||
|
minify: process.env.NO_MINIFY ? false : true,
|
||||||
|
sourcemap: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let esbuild generate the build
|
||||||
|
const build = async () => {
|
||||||
|
const result = await esbuild.build(options).catch(() => process.exit(1))
|
||||||
|
|
||||||
|
if (process.env.VERBOSE) {
|
||||||
|
const info = await esbuild.analyzeMetafile(result.metafile)
|
||||||
|
console.log(info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build()
|
4
designs/naomiwu/data.mjs
Normal file
4
designs/naomiwu/data.mjs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// This file is auto-generated | All changes you make will be overwritten.
|
||||||
|
export const name = '@freesewing/naomiwu'
|
||||||
|
export const version = '3.1.0'
|
||||||
|
export const data = { name, version }
|
104
designs/naomiwu/i18n/de.json
Normal file
104
designs/naomiwu/i18n/de.json
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
"t": "Naomi Wu Cargo Skirt",
|
||||||
|
"d": "This is Naomi's Wu's signature cargo skirt design.",
|
||||||
|
"s": {},
|
||||||
|
"o": {
|
||||||
|
"backAttachmentDepth": {
|
||||||
|
"t": "Back attachment depth",
|
||||||
|
"d": "Controls the depth of the back attachment."
|
||||||
|
},
|
||||||
|
"backAttachmentFlapChamferSize": {
|
||||||
|
"t": "Back attachment flap chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back attachment flap."
|
||||||
|
},
|
||||||
|
"backAttachmentWidth": {
|
||||||
|
"t": "Back attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"backPocketChamferSize": {
|
||||||
|
"t": "Back pocket chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back pocket."
|
||||||
|
},
|
||||||
|
"backPocketDepth": {
|
||||||
|
"t": "Back pocket depth",
|
||||||
|
"d": "Controls the depth of the back pockets."
|
||||||
|
},
|
||||||
|
"beltloopWidth": {
|
||||||
|
"t": "Beltloop width",
|
||||||
|
"d": "Controls the width of the beltloops."
|
||||||
|
},
|
||||||
|
"dartLength": {
|
||||||
|
"t": "Dart length",
|
||||||
|
"d": "Controls the length of the darts at the back."
|
||||||
|
},
|
||||||
|
"dartWidth": {
|
||||||
|
"t": "Dart width",
|
||||||
|
"d": "Controls the width of the darts at the back."
|
||||||
|
},
|
||||||
|
"flyLength": {
|
||||||
|
"t": "Fly lengt",
|
||||||
|
"d": "Controls the length of the fly."
|
||||||
|
},
|
||||||
|
"flyWidth": {
|
||||||
|
"t": "Fly width",
|
||||||
|
"d": "Controls the width of the fly."
|
||||||
|
},
|
||||||
|
"frontAttachmentChamferSize": {
|
||||||
|
"t": "Front attachment chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the front attachment."
|
||||||
|
},
|
||||||
|
"frontAttachmentWidth": {
|
||||||
|
"t": "Front attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"frontHalf": {
|
||||||
|
"t": "Front half",
|
||||||
|
"d": "Controls the proportion of the skirt that will make up the front panel."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningBend": {
|
||||||
|
"t": "Front pocket opening bend",
|
||||||
|
"d": "Controls the curvature of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningDepth": {
|
||||||
|
"t": "Front pocket opening depth",
|
||||||
|
"d": "Controls the depth of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningWidth": {
|
||||||
|
"t": "Front pocket opening width",
|
||||||
|
"d": "Controls the width of the front pocket opening."
|
||||||
|
},
|
||||||
|
"hipsEase": {
|
||||||
|
"t": "Hips ease",
|
||||||
|
"d": "Controls the amount of ease at your hips."
|
||||||
|
},
|
||||||
|
"jseamBend": {
|
||||||
|
"t": "J-Seam bend",
|
||||||
|
"d": "Controls the curvature of the J-Seam, that J-shaped seam at the fly."
|
||||||
|
},
|
||||||
|
"length": {
|
||||||
|
"t": "Length",
|
||||||
|
"d": "Controls the length of the skirt."
|
||||||
|
},
|
||||||
|
"minDartWidth": {
|
||||||
|
"t": "Minimal dart width",
|
||||||
|
"d": "Controls the minimal width below which darts will be ommitted in favor of shaping at the seams."
|
||||||
|
},
|
||||||
|
"seatEase": {
|
||||||
|
"t": "Seat ease",
|
||||||
|
"d": "Controls the amount of ease at your seat."
|
||||||
|
},
|
||||||
|
"waistbandOverlap": {
|
||||||
|
"t": "Waistband overlap",
|
||||||
|
"d": "Controls how much the waistband overlaps at the front closure."
|
||||||
|
},
|
||||||
|
"waistbandWidth": {
|
||||||
|
"t": "Waistband width",
|
||||||
|
"d": "Controls the width of the waistband."
|
||||||
|
},
|
||||||
|
"waistSlant": {
|
||||||
|
"t": "Waist slant",
|
||||||
|
"d": "Controls the slant of the waistband, how much the back is raised higher than the front."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p": {}
|
||||||
|
}
|
137
designs/naomiwu/i18n/en.json
Normal file
137
designs/naomiwu/i18n/en.json
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
{
|
||||||
|
"t": "Naomi Wu Cargo Skirt",
|
||||||
|
"d": "This is Naomi's Wu's signature cargo skirt design.",
|
||||||
|
"p": {
|
||||||
|
"backAttachmentBack": "Back Attachment Back",
|
||||||
|
"backAttachmentFlap": "Back Attachment Flap",
|
||||||
|
"backAttachmentFront": "Back Attachment Front",
|
||||||
|
"backPocket": "Back Pocket",
|
||||||
|
"backPocketFlap": "Back Pocket Flap",
|
||||||
|
"back": "Back",
|
||||||
|
"beltLoop": "Belt Loop",
|
||||||
|
"backBeltLoop": "Back Belt Loop",
|
||||||
|
"flyShield": "Fly Shield",
|
||||||
|
"frontAttachmentFacing": "Front Attachment Facing",
|
||||||
|
"frontAttachment": "Front Attachment",
|
||||||
|
"frontBase": "Front Base",
|
||||||
|
"frontFlySide": "Front fly side",
|
||||||
|
"frontNoFlySide": "Front no-fly side",
|
||||||
|
"frontNoFlySideLeft": "Front no-fly side (left)",
|
||||||
|
"frontNoFlySideRight": "Front no-fly side (right)",
|
||||||
|
"frontFlySideLeft": "Front fly side (left)",
|
||||||
|
"frontFlySideRight": "Front fly side (right)",
|
||||||
|
"frontPocketBag": "Front Pocket Bag",
|
||||||
|
"frontPocketFacing": "Front Pocket Facing",
|
||||||
|
"shared": "Shared Code",
|
||||||
|
"waistband": "Waistband"
|
||||||
|
},
|
||||||
|
"s": {
|
||||||
|
"backAttachmentTooWide": "The **Back attachement** is currently wider than the space between the belt loops.\n\nYou can decrease the width until it fits, or you can leave it as-is but then you will need to modify the beltloop spacing yourself.",
|
||||||
|
"cutBackAttachmentBack.t": "The back attachement back is not shown",
|
||||||
|
"cutBackAttachmentBack.d": "The **Back attachement back** is a rectangular piece of fabric {{{ width }}} wide and {{{ length }}} long (this includes seam allowance). This part is not shown because the **expand** core setting is currently disabled. Enable it to show this pattern part.",
|
||||||
|
"cutBeltLoop.t": "The belt loop is not shown",
|
||||||
|
"cutBeltLoop.d": "The **Belt loop** is a rectangular piece of fabric {{{ width }}} wide and {{{ length }}} long (this includes seam allowance). You need 6 of them. This part is not shown because the **expand** core setting is currently disabled. Enable it to show this pattern part.",
|
||||||
|
"cutBackBeltLoop.t": "The back belt loop is not shown",
|
||||||
|
"cutBackBeltLoop.d": "The **Back belt loop** is a rectangular piece of fabric {{{ width }}} wide and {{{ length }}} long (this includes seam allowance). This part is not shown because the **expand** core setting is currently disabled. Enable it to show this pattern part.",
|
||||||
|
"cutFlyShield.t": "The fly shield is not shown",
|
||||||
|
"cutFlyShield.d": "The **Fly shield** is a rectangular piece of fabric {{{ width }}} wide and {{{ length }}} long (this includes seam allowance). This part is not shown because the **expand** core setting is currently disabled. Enable it to show this pattern part."
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"backAttachmentDepth": {
|
||||||
|
"t": "Back attachment depth",
|
||||||
|
"d": "Controls the depth of the back attachment."
|
||||||
|
},
|
||||||
|
"backAttachmentFlapChamferSize": {
|
||||||
|
"t": "Back attachment flap chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back attachment flap."
|
||||||
|
},
|
||||||
|
"backAttachmentWidth": {
|
||||||
|
"t": "Back attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"backPocketChamferSize": {
|
||||||
|
"t": "Back pocket chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back pocket."
|
||||||
|
},
|
||||||
|
"backPocketDepth": {
|
||||||
|
"t": "Back pocket depth",
|
||||||
|
"d": "Controls the depth of the back pockets."
|
||||||
|
},
|
||||||
|
"beltLoopWidth": {
|
||||||
|
"t": "Belt loop width",
|
||||||
|
"d": "Controls the width of the belt loops."
|
||||||
|
},
|
||||||
|
"dartLength": {
|
||||||
|
"t": "Back dart length",
|
||||||
|
"d": "Controls the length of the darts at the back."
|
||||||
|
},
|
||||||
|
"dartWidth": {
|
||||||
|
"t": "Back dart width",
|
||||||
|
"d": "Controls the width of the darts at the back."
|
||||||
|
},
|
||||||
|
"flyLength": {
|
||||||
|
"t": "Fly lengt",
|
||||||
|
"d": "Controls the length of the fly."
|
||||||
|
},
|
||||||
|
"flyWidth": {
|
||||||
|
"t": "Fly width",
|
||||||
|
"d": "Controls the width of the fly."
|
||||||
|
},
|
||||||
|
"frontAttachmentChamferSize": {
|
||||||
|
"t": "Front attachment chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the front attachment."
|
||||||
|
},
|
||||||
|
"frontAttachmentWidth": {
|
||||||
|
"t": "Front attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"frontHalf": {
|
||||||
|
"t": "Front half proportion",
|
||||||
|
"d": "Controls the proportion of the skirt that will make up the front panel."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningBend": {
|
||||||
|
"t": "Front pocket opening bend",
|
||||||
|
"d": "Controls the curvature of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningDepth": {
|
||||||
|
"t": "Front pocket opening depth",
|
||||||
|
"d": "Controls the depth of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningWidth": {
|
||||||
|
"t": "Front pocket opening width",
|
||||||
|
"d": "Controls the width of the front pocket opening."
|
||||||
|
},
|
||||||
|
"hipsEase": {
|
||||||
|
"t": "Hips ease",
|
||||||
|
"d": "Controls the amount of ease at your hips."
|
||||||
|
},
|
||||||
|
"invertFly": {
|
||||||
|
"t": "Invert the side of the fly",
|
||||||
|
"d": "Allows you to control the side the fly is on, for convenience of gender-expression."
|
||||||
|
},
|
||||||
|
"jseamBend": {
|
||||||
|
"t": "J-Seam bend",
|
||||||
|
"d": "Controls the curvature of the J-Seam, that J-shaped seam at the fly."
|
||||||
|
},
|
||||||
|
"length": {
|
||||||
|
"t": "Length",
|
||||||
|
"d": "Controls the length of the skirt."
|
||||||
|
},
|
||||||
|
"minDartWidth": {
|
||||||
|
"t": "Minimal dart width",
|
||||||
|
"d": "Controls the minimal width below which darts will be ommitted in favor of shaping at the seams."
|
||||||
|
},
|
||||||
|
"seatEase": {
|
||||||
|
"t": "Seat ease",
|
||||||
|
"d": "Controls the amount of ease at your seat."
|
||||||
|
},
|
||||||
|
"waistbandWidth": {
|
||||||
|
"t": "Waistband width",
|
||||||
|
"d": "Controls the width of the waistband."
|
||||||
|
},
|
||||||
|
"waistSlant": {
|
||||||
|
"t": "Waist slant",
|
||||||
|
"d": "Controls the slant of the waistband, how much the back is raised higher than the front."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
designs/naomiwu/i18n/es.json
Normal file
104
designs/naomiwu/i18n/es.json
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
"t": "Naomi Wu Cargo Skirt",
|
||||||
|
"d": "This is Naomi's Wu's signature cargo skirt design.",
|
||||||
|
"s": {},
|
||||||
|
"o": {
|
||||||
|
"backAttachmentDepth": {
|
||||||
|
"t": "Back attachment depth",
|
||||||
|
"d": "Controls the depth of the back attachment."
|
||||||
|
},
|
||||||
|
"backAttachmentFlapChamferSize": {
|
||||||
|
"t": "Back attachment flap chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back attachment flap."
|
||||||
|
},
|
||||||
|
"backAttachmentWidth": {
|
||||||
|
"t": "Back attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"backPocketChamferSize": {
|
||||||
|
"t": "Back pocket chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back pocket."
|
||||||
|
},
|
||||||
|
"backPocketDepth": {
|
||||||
|
"t": "Back pocket depth",
|
||||||
|
"d": "Controls the depth of the back pockets."
|
||||||
|
},
|
||||||
|
"beltloopWidth": {
|
||||||
|
"t": "Beltloop width",
|
||||||
|
"d": "Controls the width of the beltloops."
|
||||||
|
},
|
||||||
|
"dartLength": {
|
||||||
|
"t": "Dart length",
|
||||||
|
"d": "Controls the length of the darts at the back."
|
||||||
|
},
|
||||||
|
"dartWidth": {
|
||||||
|
"t": "Dart width",
|
||||||
|
"d": "Controls the width of the darts at the back."
|
||||||
|
},
|
||||||
|
"flyLength": {
|
||||||
|
"t": "Fly lengt",
|
||||||
|
"d": "Controls the length of the fly."
|
||||||
|
},
|
||||||
|
"flyWidth": {
|
||||||
|
"t": "Fly width",
|
||||||
|
"d": "Controls the width of the fly."
|
||||||
|
},
|
||||||
|
"frontAttachmentChamferSize": {
|
||||||
|
"t": "Front attachment chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the front attachment."
|
||||||
|
},
|
||||||
|
"frontAttachmentWidth": {
|
||||||
|
"t": "Front attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"frontHalf": {
|
||||||
|
"t": "Front half",
|
||||||
|
"d": "Controls the proportion of the skirt that will make up the front panel."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningBend": {
|
||||||
|
"t": "Front pocket opening bend",
|
||||||
|
"d": "Controls the curvature of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningDepth": {
|
||||||
|
"t": "Front pocket opening depth",
|
||||||
|
"d": "Controls the depth of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningWidth": {
|
||||||
|
"t": "Front pocket opening width",
|
||||||
|
"d": "Controls the width of the front pocket opening."
|
||||||
|
},
|
||||||
|
"hipsEase": {
|
||||||
|
"t": "Hips ease",
|
||||||
|
"d": "Controls the amount of ease at your hips."
|
||||||
|
},
|
||||||
|
"jseamBend": {
|
||||||
|
"t": "J-Seam bend",
|
||||||
|
"d": "Controls the curvature of the J-Seam, that J-shaped seam at the fly."
|
||||||
|
},
|
||||||
|
"length": {
|
||||||
|
"t": "Length",
|
||||||
|
"d": "Controls the length of the skirt."
|
||||||
|
},
|
||||||
|
"minDartWidth": {
|
||||||
|
"t": "Minimal dart width",
|
||||||
|
"d": "Controls the minimal width below which darts will be ommitted in favor of shaping at the seams."
|
||||||
|
},
|
||||||
|
"seatEase": {
|
||||||
|
"t": "Seat ease",
|
||||||
|
"d": "Controls the amount of ease at your seat."
|
||||||
|
},
|
||||||
|
"waistbandOverlap": {
|
||||||
|
"t": "Waistband overlap",
|
||||||
|
"d": "Controls how much the waistband overlaps at the front closure."
|
||||||
|
},
|
||||||
|
"waistbandWidth": {
|
||||||
|
"t": "Waistband width",
|
||||||
|
"d": "Controls the width of the waistband."
|
||||||
|
},
|
||||||
|
"waistSlant": {
|
||||||
|
"t": "Waist slant",
|
||||||
|
"d": "Controls the slant of the waistband, how much the back is raised higher than the front."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p": {}
|
||||||
|
}
|
104
designs/naomiwu/i18n/fr.json
Normal file
104
designs/naomiwu/i18n/fr.json
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
"t": "Naomi Wu Cargo Skirt",
|
||||||
|
"d": "This is Naomi's Wu's signature cargo skirt design.",
|
||||||
|
"s": {},
|
||||||
|
"o": {
|
||||||
|
"backAttachmentDepth": {
|
||||||
|
"t": "Back attachment depth",
|
||||||
|
"d": "Controls the depth of the back attachment."
|
||||||
|
},
|
||||||
|
"backAttachmentFlapChamferSize": {
|
||||||
|
"t": "Back attachment flap chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back attachment flap."
|
||||||
|
},
|
||||||
|
"backAttachmentWidth": {
|
||||||
|
"t": "Back attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"backPocketChamferSize": {
|
||||||
|
"t": "Back pocket chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back pocket."
|
||||||
|
},
|
||||||
|
"backPocketDepth": {
|
||||||
|
"t": "Back pocket depth",
|
||||||
|
"d": "Controls the depth of the back pockets."
|
||||||
|
},
|
||||||
|
"beltloopWidth": {
|
||||||
|
"t": "Beltloop width",
|
||||||
|
"d": "Controls the width of the beltloops."
|
||||||
|
},
|
||||||
|
"dartLength": {
|
||||||
|
"t": "Dart length",
|
||||||
|
"d": "Controls the length of the darts at the back."
|
||||||
|
},
|
||||||
|
"dartWidth": {
|
||||||
|
"t": "Dart width",
|
||||||
|
"d": "Controls the width of the darts at the back."
|
||||||
|
},
|
||||||
|
"flyLength": {
|
||||||
|
"t": "Fly lengt",
|
||||||
|
"d": "Controls the length of the fly."
|
||||||
|
},
|
||||||
|
"flyWidth": {
|
||||||
|
"t": "Fly width",
|
||||||
|
"d": "Controls the width of the fly."
|
||||||
|
},
|
||||||
|
"frontAttachmentChamferSize": {
|
||||||
|
"t": "Front attachment chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the front attachment."
|
||||||
|
},
|
||||||
|
"frontAttachmentWidth": {
|
||||||
|
"t": "Front attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"frontHalf": {
|
||||||
|
"t": "Front half",
|
||||||
|
"d": "Controls the proportion of the skirt that will make up the front panel."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningBend": {
|
||||||
|
"t": "Front pocket opening bend",
|
||||||
|
"d": "Controls the curvature of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningDepth": {
|
||||||
|
"t": "Front pocket opening depth",
|
||||||
|
"d": "Controls the depth of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningWidth": {
|
||||||
|
"t": "Front pocket opening width",
|
||||||
|
"d": "Controls the width of the front pocket opening."
|
||||||
|
},
|
||||||
|
"hipsEase": {
|
||||||
|
"t": "Hips ease",
|
||||||
|
"d": "Controls the amount of ease at your hips."
|
||||||
|
},
|
||||||
|
"jseamBend": {
|
||||||
|
"t": "J-Seam bend",
|
||||||
|
"d": "Controls the curvature of the J-Seam, that J-shaped seam at the fly."
|
||||||
|
},
|
||||||
|
"length": {
|
||||||
|
"t": "Length",
|
||||||
|
"d": "Controls the length of the skirt."
|
||||||
|
},
|
||||||
|
"minDartWidth": {
|
||||||
|
"t": "Minimal dart width",
|
||||||
|
"d": "Controls the minimal width below which darts will be ommitted in favor of shaping at the seams."
|
||||||
|
},
|
||||||
|
"seatEase": {
|
||||||
|
"t": "Seat ease",
|
||||||
|
"d": "Controls the amount of ease at your seat."
|
||||||
|
},
|
||||||
|
"waistbandOverlap": {
|
||||||
|
"t": "Waistband overlap",
|
||||||
|
"d": "Controls how much the waistband overlaps at the front closure."
|
||||||
|
},
|
||||||
|
"waistbandWidth": {
|
||||||
|
"t": "Waistband width",
|
||||||
|
"d": "Controls the width of the waistband."
|
||||||
|
},
|
||||||
|
"waistSlant": {
|
||||||
|
"t": "Waist slant",
|
||||||
|
"d": "Controls the slant of the waistband, how much the back is raised higher than the front."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p": {}
|
||||||
|
}
|
8
designs/naomiwu/i18n/index.mjs
Normal file
8
designs/naomiwu/i18n/index.mjs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import en from './en.json' assert { type: 'json' }
|
||||||
|
import de from './de.json' assert { type: 'json' }
|
||||||
|
import es from './es.json' assert { type: 'json' }
|
||||||
|
import fr from './fr.json' assert { type: 'json' }
|
||||||
|
import nl from './nl.json' assert { type: 'json' }
|
||||||
|
import uk from './uk.json' assert { type: 'json' }
|
||||||
|
|
||||||
|
export const i18n = { en, de, es, fr, nl, uk }
|
104
designs/naomiwu/i18n/nl.json
Normal file
104
designs/naomiwu/i18n/nl.json
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
"t": "Naomi Wu Cargo Skirt",
|
||||||
|
"d": "This is Naomi's Wu's signature cargo skirt design.",
|
||||||
|
"s": {},
|
||||||
|
"o": {
|
||||||
|
"backAttachmentDepth": {
|
||||||
|
"t": "Back attachment depth",
|
||||||
|
"d": "Controls the depth of the back attachment."
|
||||||
|
},
|
||||||
|
"backAttachmentFlapChamferSize": {
|
||||||
|
"t": "Back attachment flap chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back attachment flap."
|
||||||
|
},
|
||||||
|
"backAttachmentWidth": {
|
||||||
|
"t": "Back attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"backPocketChamferSize": {
|
||||||
|
"t": "Back pocket chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back pocket."
|
||||||
|
},
|
||||||
|
"backPocketDepth": {
|
||||||
|
"t": "Back pocket depth",
|
||||||
|
"d": "Controls the depth of the back pockets."
|
||||||
|
},
|
||||||
|
"beltloopWidth": {
|
||||||
|
"t": "Beltloop width",
|
||||||
|
"d": "Controls the width of the beltloops."
|
||||||
|
},
|
||||||
|
"dartLength": {
|
||||||
|
"t": "Dart length",
|
||||||
|
"d": "Controls the length of the darts at the back."
|
||||||
|
},
|
||||||
|
"dartWidth": {
|
||||||
|
"t": "Dart width",
|
||||||
|
"d": "Controls the width of the darts at the back."
|
||||||
|
},
|
||||||
|
"flyLength": {
|
||||||
|
"t": "Fly lengt",
|
||||||
|
"d": "Controls the length of the fly."
|
||||||
|
},
|
||||||
|
"flyWidth": {
|
||||||
|
"t": "Fly width",
|
||||||
|
"d": "Controls the width of the fly."
|
||||||
|
},
|
||||||
|
"frontAttachmentChamferSize": {
|
||||||
|
"t": "Front attachment chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the front attachment."
|
||||||
|
},
|
||||||
|
"frontAttachmentWidth": {
|
||||||
|
"t": "Front attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"frontHalf": {
|
||||||
|
"t": "Front half",
|
||||||
|
"d": "Controls the proportion of the skirt that will make up the front panel."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningBend": {
|
||||||
|
"t": "Front pocket opening bend",
|
||||||
|
"d": "Controls the curvature of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningDepth": {
|
||||||
|
"t": "Front pocket opening depth",
|
||||||
|
"d": "Controls the depth of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningWidth": {
|
||||||
|
"t": "Front pocket opening width",
|
||||||
|
"d": "Controls the width of the front pocket opening."
|
||||||
|
},
|
||||||
|
"hipsEase": {
|
||||||
|
"t": "Hips ease",
|
||||||
|
"d": "Controls the amount of ease at your hips."
|
||||||
|
},
|
||||||
|
"jseamBend": {
|
||||||
|
"t": "J-Seam bend",
|
||||||
|
"d": "Controls the curvature of the J-Seam, that J-shaped seam at the fly."
|
||||||
|
},
|
||||||
|
"length": {
|
||||||
|
"t": "Length",
|
||||||
|
"d": "Controls the length of the skirt."
|
||||||
|
},
|
||||||
|
"minDartWidth": {
|
||||||
|
"t": "Minimal dart width",
|
||||||
|
"d": "Controls the minimal width below which darts will be ommitted in favor of shaping at the seams."
|
||||||
|
},
|
||||||
|
"seatEase": {
|
||||||
|
"t": "Seat ease",
|
||||||
|
"d": "Controls the amount of ease at your seat."
|
||||||
|
},
|
||||||
|
"waistbandOverlap": {
|
||||||
|
"t": "Waistband overlap",
|
||||||
|
"d": "Controls how much the waistband overlaps at the front closure."
|
||||||
|
},
|
||||||
|
"waistbandWidth": {
|
||||||
|
"t": "Waistband width",
|
||||||
|
"d": "Controls the width of the waistband."
|
||||||
|
},
|
||||||
|
"waistSlant": {
|
||||||
|
"t": "Waist slant",
|
||||||
|
"d": "Controls the slant of the waistband, how much the back is raised higher than the front."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p": {}
|
||||||
|
}
|
104
designs/naomiwu/i18n/uk.json
Normal file
104
designs/naomiwu/i18n/uk.json
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
"t": "Naomi Wu Cargo Skirt",
|
||||||
|
"d": "This is Naomi's Wu's signature cargo skirt design.",
|
||||||
|
"s": {},
|
||||||
|
"o": {
|
||||||
|
"backAttachmentDepth": {
|
||||||
|
"t": "Back attachment depth",
|
||||||
|
"d": "Controls the depth of the back attachment."
|
||||||
|
},
|
||||||
|
"backAttachmentFlapChamferSize": {
|
||||||
|
"t": "Back attachment flap chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back attachment flap."
|
||||||
|
},
|
||||||
|
"backAttachmentWidth": {
|
||||||
|
"t": "Back attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"backPocketChamferSize": {
|
||||||
|
"t": "Back pocket chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the back pocket."
|
||||||
|
},
|
||||||
|
"backPocketDepth": {
|
||||||
|
"t": "Back pocket depth",
|
||||||
|
"d": "Controls the depth of the back pockets."
|
||||||
|
},
|
||||||
|
"beltloopWidth": {
|
||||||
|
"t": "Beltloop width",
|
||||||
|
"d": "Controls the width of the beltloops."
|
||||||
|
},
|
||||||
|
"dartLength": {
|
||||||
|
"t": "Dart length",
|
||||||
|
"d": "Controls the length of the darts at the back."
|
||||||
|
},
|
||||||
|
"dartWidth": {
|
||||||
|
"t": "Dart width",
|
||||||
|
"d": "Controls the width of the darts at the back."
|
||||||
|
},
|
||||||
|
"flyLength": {
|
||||||
|
"t": "Fly lengt",
|
||||||
|
"d": "Controls the length of the fly."
|
||||||
|
},
|
||||||
|
"flyWidth": {
|
||||||
|
"t": "Fly width",
|
||||||
|
"d": "Controls the width of the fly."
|
||||||
|
},
|
||||||
|
"frontAttachmentChamferSize": {
|
||||||
|
"t": "Front attachment chamfer size",
|
||||||
|
"d": "Controls the size of the chamfer on the front attachment."
|
||||||
|
},
|
||||||
|
"frontAttachmentWidth": {
|
||||||
|
"t": "Front attachment width",
|
||||||
|
"d": "Controls the width of the front attachment."
|
||||||
|
},
|
||||||
|
"frontHalf": {
|
||||||
|
"t": "Front half",
|
||||||
|
"d": "Controls the proportion of the skirt that will make up the front panel."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningBend": {
|
||||||
|
"t": "Front pocket opening bend",
|
||||||
|
"d": "Controls the curvature of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningDepth": {
|
||||||
|
"t": "Front pocket opening depth",
|
||||||
|
"d": "Controls the depth of the front pocket opening."
|
||||||
|
},
|
||||||
|
"frontPocketOpeningWidth": {
|
||||||
|
"t": "Front pocket opening width",
|
||||||
|
"d": "Controls the width of the front pocket opening."
|
||||||
|
},
|
||||||
|
"hipsEase": {
|
||||||
|
"t": "Hips ease",
|
||||||
|
"d": "Controls the amount of ease at your hips."
|
||||||
|
},
|
||||||
|
"jseamBend": {
|
||||||
|
"t": "J-Seam bend",
|
||||||
|
"d": "Controls the curvature of the J-Seam, that J-shaped seam at the fly."
|
||||||
|
},
|
||||||
|
"length": {
|
||||||
|
"t": "Length",
|
||||||
|
"d": "Controls the length of the skirt."
|
||||||
|
},
|
||||||
|
"minDartWidth": {
|
||||||
|
"t": "Minimal dart width",
|
||||||
|
"d": "Controls the minimal width below which darts will be ommitted in favor of shaping at the seams."
|
||||||
|
},
|
||||||
|
"seatEase": {
|
||||||
|
"t": "Seat ease",
|
||||||
|
"d": "Controls the amount of ease at your seat."
|
||||||
|
},
|
||||||
|
"waistbandOverlap": {
|
||||||
|
"t": "Waistband overlap",
|
||||||
|
"d": "Controls how much the waistband overlaps at the front closure."
|
||||||
|
},
|
||||||
|
"waistbandWidth": {
|
||||||
|
"t": "Waistband width",
|
||||||
|
"d": "Controls the width of the waistband."
|
||||||
|
},
|
||||||
|
"waistSlant": {
|
||||||
|
"t": "Waist slant",
|
||||||
|
"d": "Controls the slant of the waistband, how much the back is raised higher than the front."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p": {}
|
||||||
|
}
|
73
designs/naomiwu/package.json
Normal file
73
designs/naomiwu/package.json
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
{
|
||||||
|
"name": "@freesewing/naomiwu",
|
||||||
|
"version": "3.1.0",
|
||||||
|
"description": "A FreeSewing pattern for Naomi Wu's signature cargo skirt",
|
||||||
|
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
|
||||||
|
"homepage": "https://freesewing.org/",
|
||||||
|
"repository": "github:freesewing/freesewing",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/freesewing/freesewing/issues"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://freesewing.org/patrons/join"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"freesewing",
|
||||||
|
"design",
|
||||||
|
"diy",
|
||||||
|
"fashion",
|
||||||
|
"made to measure",
|
||||||
|
"parametric design",
|
||||||
|
"pattern",
|
||||||
|
"sewing",
|
||||||
|
"sewing pattern"
|
||||||
|
],
|
||||||
|
"type": "module",
|
||||||
|
"module": "dist/index.mjs",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"internal": "./src/index.mjs",
|
||||||
|
"default": "./dist/index.mjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "node build.mjs",
|
||||||
|
"build:all": "yarn build",
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"mbuild": "NO_MINIFY=1 node build.mjs",
|
||||||
|
"symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -",
|
||||||
|
"test": "npx mocha tests/*.test.mjs",
|
||||||
|
"vbuild": "VERBOSE=1 node build.mjs",
|
||||||
|
"lab": "cd ../../sites/lab && yarn start",
|
||||||
|
"tips": "node ../../scripts/help.mjs",
|
||||||
|
"lint": "npx eslint 'src/**' 'tests/*.mjs'",
|
||||||
|
"prettier": "npx prettier --write 'src/*.mjs' 'tests/*.mjs'",
|
||||||
|
"testci": "NODE_OPTIONS=\"--conditions=internal\" npx mocha tests/*.test.mjs --reporter ../../tests/reporters/terse.js",
|
||||||
|
"wbuild": "node build.mjs",
|
||||||
|
"wbuild:all": "yarn wbuild"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@freesewing/core": "3.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha": "10.2.0",
|
||||||
|
"chai": "4.3.10",
|
||||||
|
"@freesewing/models": "3.1.0",
|
||||||
|
"@freesewing/plugin-timing": "3.1.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/*",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public",
|
||||||
|
"tag": "latest"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18",
|
||||||
|
"npm": ">=9"
|
||||||
|
}
|
||||||
|
}
|
162
designs/naomiwu/src/back-attachment-back.mjs
Normal file
162
designs/naomiwu/src/back-attachment-back.mjs
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
import { waistband } from './waistband.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const backAttachmentBack = {
|
||||||
|
name: 'naomiwu.backAttachmentBack', // The name in design::part format
|
||||||
|
draft: draftBackAttachmentBack, // The method to call to draft this part
|
||||||
|
after: waistband, // Ensure this is drafted after the (imported) waistband part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the back of the back attachment of the skirt
|
||||||
|
*/
|
||||||
|
function draftBackAttachmentBack({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
options,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
expand,
|
||||||
|
units,
|
||||||
|
absoluteOptions,
|
||||||
|
}) {
|
||||||
|
const width = absoluteOptions.backAttachmentWidth
|
||||||
|
const height = width * options.backAttachmentDepth
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw the back of the back attachment shape
|
||||||
|
*/
|
||||||
|
points.topLeft = new Point(0, 0)
|
||||||
|
points.topRight = new Point(width, 0)
|
||||||
|
points.bottomLeft = new Point(0, height)
|
||||||
|
points.bottomRight = new Point(width, height)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add points to mark the edge of the attachment's front
|
||||||
|
* Even if expand is off, we need these in other parts
|
||||||
|
*/
|
||||||
|
points.frontLeft = points.topLeft.shiftFractionTowards(points.bottomLeft, 0.22)
|
||||||
|
points.frontRight = new Point(points.topRight.x, points.frontLeft.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We allow the user to control the back attachment, but warn them when it's
|
||||||
|
* too wide to fit between the belt loops, because that is inconvenient.
|
||||||
|
*/
|
||||||
|
if (absoluteOptions.backAttachmentWidth > store.get('backAttachmentMaxWidth')) {
|
||||||
|
store.flag.warn({
|
||||||
|
msg: 'naomiwu:backAttachmentTooWide',
|
||||||
|
replace: {
|
||||||
|
delta: units(absoluteOptions.backAttachmentWidth - store.get('backAttachmentMaxWidth')),
|
||||||
|
},
|
||||||
|
suggest: {
|
||||||
|
text: 'flag:decrease',
|
||||||
|
icon: 'down',
|
||||||
|
update: {
|
||||||
|
settings: ['options.backAttachmentWidth', options.backAttachmentWidth * 0.9],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expand) {
|
||||||
|
store.flag.preset('expandIsOn')
|
||||||
|
} else {
|
||||||
|
// Expand is off, do not draw the part but flag this to the user
|
||||||
|
store.flag.note({
|
||||||
|
msg: `naomiwu:cutBackAttachmentBack`,
|
||||||
|
replace: {
|
||||||
|
width: units(width + 2 * sa),
|
||||||
|
length: units(height + 2 * sa),
|
||||||
|
},
|
||||||
|
suggest: {
|
||||||
|
text: 'flag:show',
|
||||||
|
icon: 'expand',
|
||||||
|
update: {
|
||||||
|
settings: ['expand', 1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Also hint about expand
|
||||||
|
store.flag.preset('expandIsOff')
|
||||||
|
|
||||||
|
return part.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
.line(points.topLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the front edge line
|
||||||
|
*/
|
||||||
|
if (complete)
|
||||||
|
paths.frontEdge = new Path()
|
||||||
|
.move(points.frontLeft)
|
||||||
|
.line(points.frontRight)
|
||||||
|
.addClass('note stroke-sm dashed')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when it's requested.
|
||||||
|
* This also adds extra SA to fold under the edge.
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).addClass('fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.frontLeft.shiftFractionTowards(points.bottomRight, 0.5)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 12,
|
||||||
|
title: 'backAttachmentBack',
|
||||||
|
align: 'center',
|
||||||
|
scale: 0.666,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the logo
|
||||||
|
*/
|
||||||
|
points.logo = points.title.shift(90, 65)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo).scale(0.5)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'width',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'length',
|
||||||
|
from: points.bottomRight,
|
||||||
|
to: points.topRight,
|
||||||
|
x: points.topRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
140
designs/naomiwu/src/back-attachment-flap.mjs
Normal file
140
designs/naomiwu/src/back-attachment-flap.mjs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
import { backAttachmentFront } from './back-attachment-front.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const backAttachmentFlap = {
|
||||||
|
name: 'naomiwu.backAttachmentFlap', // The name in design::part format
|
||||||
|
draft: draftBackAttachmentFlap, // The method to call to draft this part
|
||||||
|
from: backAttachmentFront, // Draft this part starting from the (imported) `backAttachmentBack` part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the flap of the back attachment of the skirt
|
||||||
|
*/
|
||||||
|
function draftBackAttachmentFlap({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
options,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* Shorten the bottom
|
||||||
|
*/
|
||||||
|
points.bottomLeft = new Point(
|
||||||
|
points.topLeft.x,
|
||||||
|
points.velcroBottomLeft.y + points.velcroBottomLeft.dx(points.velcroBottomRight)
|
||||||
|
)
|
||||||
|
points.bottomRight = new Point(points.topRight.x, points.bottomLeft.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add chamfer
|
||||||
|
*/
|
||||||
|
const size = points.frontRight.x * options.backAttachmentFlapChamferSize
|
||||||
|
points.chamferLeftTop = points.bottomLeft.shift(90, size)
|
||||||
|
points.chamferLeftBottom = points.bottomLeft.shift(0, size)
|
||||||
|
points.chamferRightTop = points.bottomRight.shift(90, size)
|
||||||
|
points.chamferRightBottom = points.bottomRight.shift(180, size)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extend the velcro strip
|
||||||
|
*/
|
||||||
|
points.velcroBottomLeft = new Point(points.velcroBottomLeft.x, points.bottomLeft.y * 0.92)
|
||||||
|
points.velcroBottomRight = new Point(points.velcroBottomRight.x, points.velcroBottomLeft.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.chamferLeftTop)
|
||||||
|
.line(points.chamferLeftBottom)
|
||||||
|
.line(points.chamferRightBottom)
|
||||||
|
.line(points.chamferRightTop)
|
||||||
|
.line(points.topRight)
|
||||||
|
.line(points.topLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark the velcro strip
|
||||||
|
*/
|
||||||
|
if (complete) {
|
||||||
|
paths.velcro = new Path()
|
||||||
|
.move(points.velcroTopLeft)
|
||||||
|
.line(points.velcroBottomLeft)
|
||||||
|
.line(points.velcroBottomRight)
|
||||||
|
.line(points.velcroTopRight)
|
||||||
|
.line(points.velcroTopLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('note stroke-sm dashed')
|
||||||
|
macro('banner', {
|
||||||
|
path: paths.velcro,
|
||||||
|
text: 'velcro',
|
||||||
|
classes: 'fill-note text-xs',
|
||||||
|
spaces: 2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when it's requested.
|
||||||
|
* This also adds extra SA to fold under the edge.
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).close().addClass('fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.topLeft.shift(-90, 25).shift(0, 10)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 14,
|
||||||
|
title: 'backAttachmentFlap',
|
||||||
|
scale: 0.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the logo
|
||||||
|
*/
|
||||||
|
points.logo = points.title.shift(-90, 30)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo).scale(0.333)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'width',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'length',
|
||||||
|
from: points.bottomRight,
|
||||||
|
to: points.topRight,
|
||||||
|
x: points.topRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'chamferWidth',
|
||||||
|
from: points.chamferRightBottom,
|
||||||
|
to: points.chamferRightTop,
|
||||||
|
y: points.chamferRightTop.y - 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
121
designs/naomiwu/src/back-attachment-front.mjs
Normal file
121
designs/naomiwu/src/back-attachment-front.mjs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
import { backAttachmentBack } from './back-attachment-back.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const backAttachmentFront = {
|
||||||
|
name: 'naomiwu.backAttachmentFront', // The name in design::part format
|
||||||
|
draft: draftBackAttachmentFront, // The method to call to draft this part
|
||||||
|
from: backAttachmentBack, // Draft this part starting from the (imported) `backAttachmentBack` part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the front of the back attachment of the skirt
|
||||||
|
*/
|
||||||
|
function draftBackAttachmentFront({ points, Path, paths, store, part, complete, sa, macro }) {
|
||||||
|
/*
|
||||||
|
* Clear up what we don't need from the backAttachmentBack part
|
||||||
|
*/
|
||||||
|
delete paths.frontEdge
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add points for the velcro strip
|
||||||
|
*/
|
||||||
|
points.velcroTopLeft = points.frontLeft
|
||||||
|
.shiftFractionTowards(points.frontRight, 0.4)
|
||||||
|
.shift(-90, points.frontRight.x / 10)
|
||||||
|
points.velcroTopRight = points.frontRight
|
||||||
|
.shiftFractionTowards(points.frontLeft, 0.4)
|
||||||
|
.shift(-90, points.frontRight.x / 10)
|
||||||
|
points.velcroBottomLeft = points.velcroTopLeft.shift(-90, points.frontRight.x / 3)
|
||||||
|
points.velcroBottomRight = points.velcroTopRight.shift(-90, points.frontRight.x / 3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.frontLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.line(points.frontRight)
|
||||||
|
.line(points.frontLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark the velcro strip
|
||||||
|
*/
|
||||||
|
if (complete) {
|
||||||
|
paths.velcro = new Path()
|
||||||
|
.move(points.velcroTopLeft)
|
||||||
|
.line(points.velcroBottomLeft)
|
||||||
|
.line(points.velcroBottomRight)
|
||||||
|
.line(points.velcroTopRight)
|
||||||
|
.line(points.velcroTopLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('note stroke-sm dashed')
|
||||||
|
macro('banner', {
|
||||||
|
path: paths.velcro,
|
||||||
|
text: 'velcro',
|
||||||
|
classes: 'fill-note text-xs',
|
||||||
|
spaces: 2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when it's requested.
|
||||||
|
* This also adds extra SA to fold under the edge.
|
||||||
|
*/
|
||||||
|
if (sa)
|
||||||
|
paths.sa = new Path()
|
||||||
|
.move(points.frontLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.line(points.frontRight)
|
||||||
|
.offset(sa)
|
||||||
|
.join(
|
||||||
|
new Path()
|
||||||
|
.move(points.frontRight)
|
||||||
|
.line(points.frontLeft)
|
||||||
|
.offset(3 * sa)
|
||||||
|
)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.frontLeft.shiftFractionTowards(points.bottomRight, 0.5)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 13,
|
||||||
|
title: 'backAttachmentFront',
|
||||||
|
align: 'center',
|
||||||
|
scale: 0.666,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'width',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'length',
|
||||||
|
from: points.bottomRight,
|
||||||
|
to: points.frontRight,
|
||||||
|
x: points.topRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
136
designs/naomiwu/src/back-belt-loop.mjs
Normal file
136
designs/naomiwu/src/back-belt-loop.mjs
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const backBeltLoop = {
|
||||||
|
name: 'naomiwu.backBeltLoop', // The name in design::part format
|
||||||
|
draft: draftBackBeltLoop, // The method to call to draft this part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the waistband of the skirt
|
||||||
|
*/
|
||||||
|
function draftBackBeltLoop({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
sa,
|
||||||
|
expand,
|
||||||
|
units,
|
||||||
|
macro,
|
||||||
|
absoluteOptions,
|
||||||
|
}) {
|
||||||
|
const w = absoluteOptions.beltLoopWidth * 4.5
|
||||||
|
const h = absoluteOptions.waistbandWidth * 1.5
|
||||||
|
|
||||||
|
if (expand) {
|
||||||
|
store.flag.preset('expandIsOn')
|
||||||
|
} else {
|
||||||
|
// Expand is off, do not draw the part but flag this to the user
|
||||||
|
store.flag.note({
|
||||||
|
msg: `naomiwu:cutBackBeltLoop`,
|
||||||
|
replace: {
|
||||||
|
width: units(w + 4 * sa),
|
||||||
|
length: units(h + 2 * sa),
|
||||||
|
},
|
||||||
|
suggest: {
|
||||||
|
text: 'flag:show',
|
||||||
|
icon: 'expand',
|
||||||
|
update: {
|
||||||
|
settings: ['expand', 1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Also hint about expand
|
||||||
|
store.flag.preset('expandIsOff')
|
||||||
|
|
||||||
|
return part.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's a rectangle
|
||||||
|
*/
|
||||||
|
points.topLeft = new Point(0, 0)
|
||||||
|
points.topRight = new Point(w, 0)
|
||||||
|
points.bottomLeft = new Point(0, h)
|
||||||
|
points.bottomRight = new Point(w, h)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Seamline
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
.line(points.topLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when requested (note that this adds extra SA at the sides for hemming)
|
||||||
|
*/
|
||||||
|
if (sa)
|
||||||
|
paths.sa = new Path()
|
||||||
|
.move(points.topLeft.shift(180, sa))
|
||||||
|
.line(points.bottomLeft.shift(180, sa))
|
||||||
|
.line(points.bottomRight.shift(0, sa))
|
||||||
|
.line(points.topRight.shift(0, sa))
|
||||||
|
.line(points.topLeft.shift(180, sa))
|
||||||
|
.close()
|
||||||
|
.offset(sa)
|
||||||
|
.addClass('fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 6, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.topLeft.shiftFractionTowards(points.bottomRight, 0.5)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 15,
|
||||||
|
title: 'beltLoop',
|
||||||
|
align: 'center',
|
||||||
|
scale: 0.666,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a grainline indicator
|
||||||
|
*/
|
||||||
|
points.grainlineTop = points.topLeft.shift(0, 7)
|
||||||
|
points.grainlineBottom = points.bottomLeft.shift(0, 7)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
classes: {
|
||||||
|
line: 'stroke-sm note',
|
||||||
|
text: 'text-sm fill-note center',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wFull',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + 15 + sa,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hFull',
|
||||||
|
from: points.bottomRight,
|
||||||
|
to: points.topRight,
|
||||||
|
x: points.topRight.x + 15 + 2 * sa,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
93
designs/naomiwu/src/back-pocket-flap.mjs
Normal file
93
designs/naomiwu/src/back-pocket-flap.mjs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import { backPocket } from './back-pocket.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const backPocketFlap = {
|
||||||
|
name: 'naomiwu.backPocketFlap', // The name in design::part format
|
||||||
|
draft: draftBackPocketFlap, // The method to call to draft this part
|
||||||
|
from: backPocket, // Draft this part starting from the (imported) `backPocket` part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the back pocket flap of the skirt
|
||||||
|
*/
|
||||||
|
function draftBackPocketFlap({ Point, points, paths, store, part, sa, snippets, Snippet, macro }) {
|
||||||
|
/*
|
||||||
|
* Clean up what we don't need from the backPocket part
|
||||||
|
*/
|
||||||
|
delete paths.pocket
|
||||||
|
macro('rmvd', 'height')
|
||||||
|
macro('rmhd', 'width')
|
||||||
|
macro('rmhd', 'wChamfer')
|
||||||
|
macro('rmvd', 'hChamfer')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = paths.flap.clone().setClass('fabric')
|
||||||
|
paths.flap.hide()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when it's requested
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 2, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.pocketTopLeft.shiftFractionTowards(points.flapBottomLeft, 0.6).shift(0, 20)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 11,
|
||||||
|
title: 'backPocketFlap',
|
||||||
|
scale: 0.7,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the logo
|
||||||
|
*/
|
||||||
|
points.logo = points.title.shift(0, 70)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo).scale(0.5)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a grainline indicator
|
||||||
|
*/
|
||||||
|
points.grainlineBottom = points.flapBottomLeft.shift(0, 10)
|
||||||
|
points.grainlineTop = new Point(points.grainlineBottom.x, points.flapTopRight.y)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('vd', {
|
||||||
|
id: 'leftHeight',
|
||||||
|
from: points.flapBottomLeft,
|
||||||
|
to: points.flapTopLeft,
|
||||||
|
x: points.flapTopLeft.x - sa - 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'rightHeight',
|
||||||
|
from: points.flapBottomRight,
|
||||||
|
to: points.flapTopRight,
|
||||||
|
x: points.flapTopRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'width',
|
||||||
|
from: points.flapTopLeft,
|
||||||
|
to: points.flapTopRight,
|
||||||
|
y: points.flapTopRight.y - sa - 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
132
designs/naomiwu/src/back-pocket.mjs
Normal file
132
designs/naomiwu/src/back-pocket.mjs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
import { back } from './back.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const backPocket = {
|
||||||
|
name: 'naomiwu.backPocket', // The name in design::part format
|
||||||
|
draft: draftBackPocket, // The method to call to draft this part
|
||||||
|
from: back, // Draft this part starting from the (imported) `back` part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the back pocket of the skirt
|
||||||
|
*/
|
||||||
|
function draftBackPocket({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* Clean up what we don't need from the back part
|
||||||
|
*/
|
||||||
|
delete paths.cb
|
||||||
|
delete paths.hem
|
||||||
|
delete paths.hipLine
|
||||||
|
delete paths.side
|
||||||
|
delete paths.backSeam
|
||||||
|
if (!complete) delete paths.flap
|
||||||
|
delete snippets['dartLeft-bnotch']
|
||||||
|
delete snippets['dartRight-bnotch']
|
||||||
|
delete snippets['dartTip-bnotch']
|
||||||
|
macro('rmad')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.pocket.hide()
|
||||||
|
paths.seam = paths.pocket.clone().setClass('fabric').unhide()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when it's requested.
|
||||||
|
* This also adds extra SA to fold under the edge.
|
||||||
|
*/
|
||||||
|
if (sa)
|
||||||
|
paths.sa = new Path()
|
||||||
|
.move(points.pocketTopLeft)
|
||||||
|
.line(points.chamferLeftTop)
|
||||||
|
.line(points.chamferLeft)
|
||||||
|
.line(points.chamferRight)
|
||||||
|
.line(points.chamferRightTop)
|
||||||
|
.line(points.pocketTopRight)
|
||||||
|
.offset(sa)
|
||||||
|
.join(
|
||||||
|
new Path()
|
||||||
|
.move(points.pocketTopRight)
|
||||||
|
.line(points.pocketTopLeft)
|
||||||
|
.offset(3 * sa)
|
||||||
|
)
|
||||||
|
.close()
|
||||||
|
.attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 2, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.pocketTopLeft.shiftFractionTowards(points.chamferLeft, 0.5)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 10,
|
||||||
|
title: 'backPocket',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the logo
|
||||||
|
*/
|
||||||
|
points.logo = points.title.shift(20, 80)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo).scale(0.5)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the grainline indicator
|
||||||
|
*/
|
||||||
|
points.grainlineBottom = points.chamferRight.shiftFractionTowards(points.chamferLeft, 0.1)
|
||||||
|
points.grainlineTop = new Point(points.grainlineBottom.x, points.pocketTopRight.y)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wChamfer',
|
||||||
|
from: points.chamferRight,
|
||||||
|
to: points.chamferRightTop,
|
||||||
|
y: points.chamferLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'width',
|
||||||
|
from: points.chamferLeftTop,
|
||||||
|
to: points.chamferRightTop,
|
||||||
|
y: points.chamferLeft.y + sa + 30,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hChamfer',
|
||||||
|
from: points.chamferRight,
|
||||||
|
to: points.chamferRightTop,
|
||||||
|
x: points.pocketTopRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'height',
|
||||||
|
from: points.chamferRight,
|
||||||
|
to: points.pocketTopRight,
|
||||||
|
x: points.pocketTopRight.x + sa + 30,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
405
designs/naomiwu/src/back.mjs
Normal file
405
designs/naomiwu/src/back.mjs
Normal file
|
@ -0,0 +1,405 @@
|
||||||
|
import { shared } from './shared.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const back = {
|
||||||
|
name: 'naomiwu.back', // The name in design::part format
|
||||||
|
draft: draftBack, // The method to call to draft this part
|
||||||
|
after: shared, // Indicate the `shared` part (see import above) needs to be drafted prior to this part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the back panel of the skirt
|
||||||
|
*/
|
||||||
|
function draftBack({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
options,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
absoluteOptions,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* How much we need to reduce from seat to hips
|
||||||
|
*/
|
||||||
|
const reduce = store.get('hipsQuarterReduction')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do we need to add darts?
|
||||||
|
* Shaping happens at both back panels, so everthing we take out is doubled.
|
||||||
|
* In addition, shaping happens on both side seam and dart, so doubled again
|
||||||
|
* So only if the total reduction is more than 4x the minimal dart width do we add darts
|
||||||
|
*/
|
||||||
|
store.set(
|
||||||
|
'darts',
|
||||||
|
store.get('hipsQuarterReduction') > 4 * absoluteOptions.minDartWidth ? true : false
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How much shaping should we add in the panel?
|
||||||
|
*/
|
||||||
|
const shaping = store.get('darts') ? reduce - absoluteOptions.dartWidth * 2 : reduce
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We start with drawing a simple skirt outline for the back panel
|
||||||
|
*/
|
||||||
|
points.topLeft = new Point(shaping / 2, 0)
|
||||||
|
points.topCp = new Point(store.get('backQuarterHips') / 2, 0)
|
||||||
|
points.topRight = new Point(
|
||||||
|
points.topLeft.x + store.get('backQuarterHips'),
|
||||||
|
absoluteOptions.waistSlant
|
||||||
|
)
|
||||||
|
points.bottomLeft = new Point(0, points.topRight.y + absoluteOptions.length)
|
||||||
|
points.bottomRight = new Point(store.get('backQuarterSeat'), points.bottomLeft.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To find the top of the dart is easy if the waistline is a straight line.
|
||||||
|
* However, if the `waistSlant` option is non-zero, the waistline will be a curve.
|
||||||
|
* So we need to follow that curve to find a point on it to use as the middle for the dart.
|
||||||
|
* Store the hipline curve/line so we can re-use it later, but hide it from the output.
|
||||||
|
*/
|
||||||
|
paths.hipLine =
|
||||||
|
options.waistSlant > 0
|
||||||
|
? new Path().move(points.topRight)._curve(points.topCp, points.topLeft).hide()
|
||||||
|
: new Path().move(points.topRight).line(points.topLeft).hide()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store the waist length so we can accurately notch the waistband
|
||||||
|
*/
|
||||||
|
store.set('backHipLength', paths.hipLine.length())
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add back darts, but only if they are not too narrow to sew
|
||||||
|
*/
|
||||||
|
if (store.get('darts')) {
|
||||||
|
/*
|
||||||
|
* Find the middle of the hipline
|
||||||
|
*/
|
||||||
|
points.dartTopMiddle = paths.hipLine.shiftFractionAlong(0.5)
|
||||||
|
/*
|
||||||
|
* Bottom of the dart is controlled by the dart length option which is a factor
|
||||||
|
* of the distance between hipline and seatline.
|
||||||
|
*/
|
||||||
|
points.dartTip = points.dartTopMiddle.shift(-90, absoluteOptions.dartLength)
|
||||||
|
/*
|
||||||
|
* Now open up the dart
|
||||||
|
*/
|
||||||
|
const len = store.get('backHipLength')
|
||||||
|
points.dartRight = paths.hipLine.shiftAlong(len / 2 - absoluteOptions.dartWidth)
|
||||||
|
points.dartLeft = paths.hipLine.shiftAlong(len / 2 + absoluteOptions.dartWidth)
|
||||||
|
/*
|
||||||
|
* Finally, move the topRight point outwards to compensate for the draft shaping
|
||||||
|
* If the hipLine is curved, this is not a 100% accurate match as we need to extende the
|
||||||
|
* curve further than it goes. However, by going in a straight line from the dartRight
|
||||||
|
* to the topRight point, we will follow the general direction of the curve and things will
|
||||||
|
* smooth out
|
||||||
|
*/
|
||||||
|
points.topRight = points.dartRight.shiftOutwards(points.topRight, absoluteOptions.dartWidth * 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw the back pockets, or at least their outline
|
||||||
|
* We only create the points here, we will only include this outline of the user requests a
|
||||||
|
* complete pattern (see below)
|
||||||
|
*/
|
||||||
|
points.waistCenter = points.topLeft.shiftFractionTowards(points.topRight, 0.5)
|
||||||
|
points.hemCenter = new Point(points.waistCenter.x, points.bottomRight.y)
|
||||||
|
points.pocketBottomRight = points.hemCenter.shiftFractionTowards(points.bottomRight, 0.75)
|
||||||
|
points.pocketBottomLeft = points.hemCenter.shiftFractionTowards(points.bottomRight, -0.75)
|
||||||
|
points.pocketTopRight = points.pocketBottomRight.shift(
|
||||||
|
-90,
|
||||||
|
points.pocketBottomRight.dy(points.topRight) * options.backPocketDepth
|
||||||
|
)
|
||||||
|
points.pocketTopLeft = new Point(points.pocketBottomLeft.x, points.pocketTopRight.y)
|
||||||
|
points.chamferLeft = points.pocketBottomLeft.shiftFractionTowards(
|
||||||
|
points.pocketBottomRight,
|
||||||
|
options.backPocketChamferSize
|
||||||
|
)
|
||||||
|
points.chamferRight = points.pocketBottomRight.shiftFractionTowards(
|
||||||
|
points.pocketBottomLeft,
|
||||||
|
options.backPocketChamferSize
|
||||||
|
)
|
||||||
|
points.chamferLeftTop = points.chamferLeft.rotate(90, points.pocketBottomLeft)
|
||||||
|
points.chamferRightTop = new Point(points.pocketBottomRight.x, points.chamferLeftTop.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Also draw the back pocket flap outline
|
||||||
|
* We only create the points here, we will only include this outline of the user requests a
|
||||||
|
* complete pattern (see below)
|
||||||
|
*/
|
||||||
|
points.flapTopLeft = points.pocketTopRight.shiftFractionTowards(points.pocketTopLeft, 1.02)
|
||||||
|
points.flapTopRight = points.pocketTopLeft.shiftFractionTowards(points.pocketTopRight, 1.02)
|
||||||
|
points.flapBottomLeft = points.flapTopLeft.shift(
|
||||||
|
-90,
|
||||||
|
points.flapTopLeft.dy(points.pocketBottomLeft) / 3
|
||||||
|
)
|
||||||
|
points.flapBottomRight = points.flapTopRight.shift(
|
||||||
|
-90,
|
||||||
|
points.flapTopLeft.dy(points.pocketBottomLeft) / 4
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw the actual seamline
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
if (store.get('darts')) {
|
||||||
|
paths.seam = paths.seam
|
||||||
|
.join(paths.hipLine.split(points.dartRight).shift())
|
||||||
|
.line(points.dartTip)
|
||||||
|
.line(points.dartLeft)
|
||||||
|
.join(paths.hipLine.split(points.dartLeft).pop())
|
||||||
|
} else paths.seam._curve(points.topCp, points.topLeft)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply CSS classes and close the seamline path
|
||||||
|
*/
|
||||||
|
paths.seam.addClass('fabric').close()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw the outline of the back pocket on the pattern in dashed line so that people
|
||||||
|
* have a visual guide for where the pocket should go when constructing the skirt
|
||||||
|
* (but only if the user wants a complete pattern)
|
||||||
|
*/
|
||||||
|
paths.pocket = new Path()
|
||||||
|
.move(points.pocketTopLeft)
|
||||||
|
.line(points.chamferLeftTop)
|
||||||
|
.line(points.chamferLeft)
|
||||||
|
.line(points.chamferRight)
|
||||||
|
.line(points.chamferRightTop)
|
||||||
|
.line(points.pocketTopRight)
|
||||||
|
.line(points.pocketTopLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('note dashed stroke-sm')
|
||||||
|
.hide()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does the user want seam allowance (sa) included on the pattern?
|
||||||
|
*/
|
||||||
|
if (sa) {
|
||||||
|
/*
|
||||||
|
* Our dart complicates matters, so we need a version without the dart as the SA base
|
||||||
|
* We also need to make sure the hem allowance is different/bigger
|
||||||
|
*/
|
||||||
|
paths.saBase = new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.bottomLeft.shift(-90, 2 * sa)) // extra hem SA
|
||||||
|
.line(points.bottomRight.shift(-90, 2 * sa)) // extra hem SA
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
.join(paths.hipLine)
|
||||||
|
.close()
|
||||||
|
.hide()
|
||||||
|
paths.sa = paths.saBase.offset(sa).attr('class', 'fabric sa')
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store the side seam length so we can match it in the front part
|
||||||
|
*/
|
||||||
|
store.set('sideSeam', points.topRight.dist(points.bottomRight))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user wants a complete pattern, let's add some more guidance
|
||||||
|
*/
|
||||||
|
if (complete) {
|
||||||
|
/*
|
||||||
|
* Show the pocket outline
|
||||||
|
*/
|
||||||
|
paths.pocket.unhide()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some thing with the pocket flap. Note that drawing both pocket and pocket flap
|
||||||
|
* also helps people know which side is up, so to speak.
|
||||||
|
*/
|
||||||
|
paths.flap = new Path()
|
||||||
|
.move(points.flapTopRight)
|
||||||
|
.line(points.flapTopLeft)
|
||||||
|
.line(points.flapBottomLeft)
|
||||||
|
.line(points.flapBottomRight)
|
||||||
|
.line(points.flapTopRight)
|
||||||
|
.close()
|
||||||
|
.addClass('note dashed stroke-sm')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a note on the center back seam (CB) to clarify this is center back
|
||||||
|
*/
|
||||||
|
paths.cb = new Path()
|
||||||
|
.move(points.bottomLeft)
|
||||||
|
.line(points.topLeft)
|
||||||
|
.addText('centerBack', 'center fill-note text-sm')
|
||||||
|
.attr('data-text-dy', 8)
|
||||||
|
/*
|
||||||
|
* Add a note on the side seam to clarify this is the side
|
||||||
|
*/
|
||||||
|
paths.side = new Path()
|
||||||
|
.move(points.bottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
.addClass('hidden')
|
||||||
|
.addText('sideSeam', 'center fill-note text-sm')
|
||||||
|
.attr('data-text-dy', -1)
|
||||||
|
/*
|
||||||
|
* Add a note on the hem to clarify this is the hem
|
||||||
|
*/
|
||||||
|
paths.hem = new Path()
|
||||||
|
.move(points.bottomLeft)
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.addClass('hidden')
|
||||||
|
.addText('hem', 'center fill-note text-sm')
|
||||||
|
.attr('data-text-dy', -1)
|
||||||
|
/*
|
||||||
|
* Add a note on the top seam to clarify this is where the waistband shoud be attached
|
||||||
|
*/
|
||||||
|
points.topRight
|
||||||
|
.addText('attachWaistband', 'fill-note right text-sm')
|
||||||
|
.attr('data-text-dy', 8)
|
||||||
|
.attr('data-text-dx', -8)
|
||||||
|
points.topLeft
|
||||||
|
.addText('attachWaistband', 'fill-note left text-sm')
|
||||||
|
.attr('data-text-dy', 8)
|
||||||
|
.attr('data-text-dx', 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 2, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add skully, the FreeSewing logo :)
|
||||||
|
*/
|
||||||
|
points.logo = points.topLeft
|
||||||
|
.shiftFractionTowards(points.bottomLeft, 0.3)
|
||||||
|
.shift(0, points.topRight.x / 4)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a title for this part
|
||||||
|
*/
|
||||||
|
points.title = points.logo.shift(-90, 70)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 1,
|
||||||
|
title: 'back',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a grainline to indicate the fabric grain
|
||||||
|
*/
|
||||||
|
points.grainlineTop = points.topRight.shift(225, 25)
|
||||||
|
points.grainlineBottom = new Point(points.grainlineTop.x, points.bottomRight.y - 25)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add (back) notches
|
||||||
|
*/
|
||||||
|
const notches = ['pocketTopLeft', 'pocketTopRight']
|
||||||
|
if (store.get('darts')) notches.push('dartLeft', 'dartRight', 'dartTip')
|
||||||
|
macro('sprinkle', {
|
||||||
|
snippet: 'bnotch',
|
||||||
|
on: notches,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add dimensions
|
||||||
|
if (points.topLeft.x > points.bottomLeft.x) {
|
||||||
|
macro('hd', {
|
||||||
|
id: 'bottomWidth',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + 3 * sa + 30,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'topLeftToBottomWidth',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + 3 * sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wCbWaistToSideWaist',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.topRight,
|
||||||
|
y: points.topLeft.y - sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'topWidth',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.topRight,
|
||||||
|
y: points.topLeft.y - sa - 30,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
macro('hd', {
|
||||||
|
id: 'bottomWidth',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + 3 * sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'topLeftToBottomWidth',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + 3 * sa + 30,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'bottomLeftToTopWidth',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.topRight,
|
||||||
|
y: points.topLeft.y - sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'topWidth',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.topRight,
|
||||||
|
y: points.topLeft.y - sa - 30,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (store.get('darts')) {
|
||||||
|
macro('hd', {
|
||||||
|
id: 'topLeftToDartWidth',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.dartLeft,
|
||||||
|
y: points.topLeft.y + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'topRightToDartWidth',
|
||||||
|
from: points.dartRight,
|
||||||
|
to: points.topRight,
|
||||||
|
y: points.topLeft.y + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'dartWidth',
|
||||||
|
from: points.dartLeft,
|
||||||
|
to: points.dartRight,
|
||||||
|
y: points.dartTip.y + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'dartLength',
|
||||||
|
from: points.dartTip,
|
||||||
|
to: points.dartRight,
|
||||||
|
x: points.dartRight.x + 15,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
macro('vd', {
|
||||||
|
id: 'rightHeight',
|
||||||
|
from: points.bottomRight,
|
||||||
|
to: points.topRight,
|
||||||
|
x: points.topRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
127
designs/naomiwu/src/belt-loop.mjs
Normal file
127
designs/naomiwu/src/belt-loop.mjs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const beltLoop = {
|
||||||
|
name: 'naomiwu.beltLoop', // The name in design::part format
|
||||||
|
draft: draftBeltLoop, // The method to call to draft this part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the waistband of the skirt
|
||||||
|
*/
|
||||||
|
function draftBeltLoop({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
sa,
|
||||||
|
expand,
|
||||||
|
units,
|
||||||
|
macro,
|
||||||
|
absoluteOptions,
|
||||||
|
}) {
|
||||||
|
const w = absoluteOptions.beltLoopWidth
|
||||||
|
const h = absoluteOptions.waistbandWidth * 1.5
|
||||||
|
|
||||||
|
if (expand) {
|
||||||
|
store.flag.preset('expandIsOn')
|
||||||
|
} else {
|
||||||
|
// Expand is off, do not draw the part but flag this to the user
|
||||||
|
store.flag.note({
|
||||||
|
msg: `naomiwu:cutBeltLoop`,
|
||||||
|
replace: {
|
||||||
|
width: units(w + 2 * sa),
|
||||||
|
length: units(h + 2 * sa),
|
||||||
|
},
|
||||||
|
suggest: {
|
||||||
|
text: 'flag:show',
|
||||||
|
icon: 'expand',
|
||||||
|
update: {
|
||||||
|
settings: ['expand', 1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Also hint about expand
|
||||||
|
store.flag.preset('expandIsOff')
|
||||||
|
|
||||||
|
return part.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's a rectangle
|
||||||
|
*/
|
||||||
|
points.topLeft = new Point(0, 0)
|
||||||
|
points.topRight = new Point(w, 0)
|
||||||
|
points.bottomLeft = new Point(0, h)
|
||||||
|
points.bottomRight = new Point(w, h)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Seamline
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
.line(points.topLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when requested
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 6, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.topLeft.shiftFractionTowards(points.bottomRight, 0.5)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 15,
|
||||||
|
title: 'beltLoop',
|
||||||
|
align: 'center',
|
||||||
|
scale: 0.333,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a grainline indicator
|
||||||
|
*/
|
||||||
|
points.grainlineTop = points.topLeft.shift(0, 5)
|
||||||
|
points.grainlineBottom = points.bottomLeft.shift(0, 5)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
classes: {
|
||||||
|
line: 'stroke-sm note',
|
||||||
|
text: 'text-xs fill-note center',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wFull',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + 15 + sa,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hFull',
|
||||||
|
from: points.bottomRight,
|
||||||
|
to: points.topRight,
|
||||||
|
x: points.topRight.x + 15 + sa,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
149
designs/naomiwu/src/fly-shield.mjs
Normal file
149
designs/naomiwu/src/fly-shield.mjs
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const flyShield = {
|
||||||
|
name: 'naomiwu.flyShield', // The name in the form of design::name
|
||||||
|
draft: draftFlyShield, // The method to call for drafting this part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the fly shield.
|
||||||
|
* Giving it a descriptive name is optional, but helps with debugging.
|
||||||
|
*/
|
||||||
|
function draftFlyShield({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
part,
|
||||||
|
complete,
|
||||||
|
store,
|
||||||
|
units,
|
||||||
|
sa,
|
||||||
|
expand,
|
||||||
|
macro,
|
||||||
|
absoluteOptions,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* Save ourselves some typing by storing width and height
|
||||||
|
*/
|
||||||
|
const w = absoluteOptions.flyWidth
|
||||||
|
const h = absoluteOptions.flyLength * 1.05 // A bit longer than the fly so the seam will catch
|
||||||
|
|
||||||
|
if (expand) {
|
||||||
|
store.flag.preset('expandIsOn')
|
||||||
|
} else {
|
||||||
|
// Expand is off, do not draw the part but flag this to the user
|
||||||
|
store.flag.note({
|
||||||
|
msg: `naomiwu:cutFlyShield`,
|
||||||
|
replace: {
|
||||||
|
width: units(w + 2 * sa),
|
||||||
|
length: units(h + 2 * sa),
|
||||||
|
},
|
||||||
|
suggest: {
|
||||||
|
text: 'flag:show',
|
||||||
|
icon: 'expand',
|
||||||
|
update: {
|
||||||
|
settings: ['expand', 1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Also hint about expand
|
||||||
|
store.flag.preset('expandIsOff')
|
||||||
|
|
||||||
|
return part.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fly shield is a simple rectangle folder in half
|
||||||
|
*/
|
||||||
|
points.topLeft = new Point(0, 0)
|
||||||
|
points.topMid = new Point(w, 0)
|
||||||
|
points.topRight = new Point(2 * w, 0)
|
||||||
|
points.bottomLeft = new Point(0, h)
|
||||||
|
points.bottomMid = new Point(w, h)
|
||||||
|
points.bottomRight = new Point(2 * w, h)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.bottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
.line(points.topLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add seam allowance only when requested
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user wants a complete pattern, let's add some more guidance
|
||||||
|
*/
|
||||||
|
if (complete) {
|
||||||
|
/*
|
||||||
|
* Indicate this needs to be folded in half
|
||||||
|
*/
|
||||||
|
paths.fold = new Path().move(points.bottomMid).line(points.topMid).addClass('note help')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a message that it needs to be holded in half
|
||||||
|
*/
|
||||||
|
macro('banner', {
|
||||||
|
path: paths.fold,
|
||||||
|
text: 'foldHere',
|
||||||
|
className: 'text-sm fill-note',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a title
|
||||||
|
*/
|
||||||
|
points.title = points.topMid.shiftFractionTowards(points.bottomMid, 0.5)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 4,
|
||||||
|
title: 'flyShield',
|
||||||
|
scale: 0.6,
|
||||||
|
align: 'center',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the grainline
|
||||||
|
*/
|
||||||
|
points.grainlineTop = points.topLeft.shiftFractionTowards(points.topMid, 0.5)
|
||||||
|
points.grainlineBottom = new Point(points.grainlineTop.x, points.bottomLeft.y)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wFull',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hFull',
|
||||||
|
from: points.bottomRight,
|
||||||
|
to: points.topRight,
|
||||||
|
x: points.bottomRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
138
designs/naomiwu/src/front-attachment-facing.mjs
Normal file
138
designs/naomiwu/src/front-attachment-facing.mjs
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
import { frontAttachment } from './front-attachment.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const frontAttachmentFacing = {
|
||||||
|
name: 'naomiwu.frontAttachmentFacing', // The name in design::part format
|
||||||
|
draft: draftFrontAttachmentFacing, // The method to call to draft this part
|
||||||
|
from: frontAttachment, // Draft this part starting from the (imported) frontAttachment part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the front attachment facing of the skirt
|
||||||
|
*/
|
||||||
|
function draftFrontAttachmentFacing({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
part,
|
||||||
|
store,
|
||||||
|
options,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* Adapt shape from the front attachment main shape
|
||||||
|
*/
|
||||||
|
points.waistLeft = points.topRight.shiftFractionTowards(
|
||||||
|
points.frontPocketStart,
|
||||||
|
options.frontAttachmentWidth
|
||||||
|
)
|
||||||
|
points.waistRight = points.frontPocketStart.shiftFractionTowards(points.topRight, 0.95)
|
||||||
|
points.startLeft = new Point(points.waistLeft.x, points.frontPocketCurveStart.y)
|
||||||
|
points.startRight = new Point(points.waistRight.x, points.frontPocketCurveStart.y)
|
||||||
|
points.edgeLeft = points.foldLeft.shiftFractionTowards(points.startLeft, -0.4)
|
||||||
|
points.edgeRight = new Point(points.waistRight.x, points.edgeLeft.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.startLeft)
|
||||||
|
.line(points.edgeLeft)
|
||||||
|
.line(points.edgeRight)
|
||||||
|
.line(points.startRight)
|
||||||
|
.line(points.startLeft)
|
||||||
|
.close()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when it's requested.
|
||||||
|
* This also adds extra SA to fold under the edge.
|
||||||
|
*/
|
||||||
|
if (sa)
|
||||||
|
paths.sa = new Path()
|
||||||
|
.move(points.startLeft)
|
||||||
|
.line(points.edgeLeft)
|
||||||
|
.line(points.edgeRight)
|
||||||
|
.line(points.startRight)
|
||||||
|
.offset(sa)
|
||||||
|
.join(
|
||||||
|
new Path()
|
||||||
|
.move(points.startRight)
|
||||||
|
.line(points.startLeft)
|
||||||
|
.offset(3 * sa)
|
||||||
|
)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.waistLeft
|
||||||
|
.shiftFractionTowards(points.waistRight, 0.1)
|
||||||
|
.shift(-90, points.foldRight.y / 1.5)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 9,
|
||||||
|
title: 'frontAttachmentFacing',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the logo
|
||||||
|
*/
|
||||||
|
points.logo = points.title.shift(-70, 70)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo).scale(0.666)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'width',
|
||||||
|
from: points.edgeLeft,
|
||||||
|
to: points.edgeRight,
|
||||||
|
y: points.edgeLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'chamferWidth',
|
||||||
|
from: points.foldLeft,
|
||||||
|
to: points.chamferLeft,
|
||||||
|
y: points.chamferLeftBottom.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'chamferHeight',
|
||||||
|
from: points.chamferLeftBottom,
|
||||||
|
to: points.chamferLeft,
|
||||||
|
x: points.chamferLeft.x + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'bottomLength',
|
||||||
|
from: points.edgeRight,
|
||||||
|
to: points.foldRight,
|
||||||
|
x: points.edgeRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'topLength',
|
||||||
|
from: points.foldRight,
|
||||||
|
to: points.startRight,
|
||||||
|
x: points.edgeRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'length',
|
||||||
|
from: points.edgeRight,
|
||||||
|
to: points.startRight,
|
||||||
|
x: points.edgeRight.x + sa + 30,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
214
designs/naomiwu/src/front-attachment.mjs
Normal file
214
designs/naomiwu/src/front-attachment.mjs
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
import { frontBase } from './front-base.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const frontAttachment = {
|
||||||
|
name: 'naomiwu.frontAttachment', // The name in design::part format
|
||||||
|
draft: draftFrontAttachment, // The method to call to draft this part
|
||||||
|
from: frontBase, // Draft this part starting from the (imported) frontBase part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the front attachment of the skirt
|
||||||
|
*/
|
||||||
|
function draftFrontAttachment({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
options,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* Draw the front attachment shape, or at least the part that's not
|
||||||
|
* made out of the main materials (aka the facing)
|
||||||
|
*/
|
||||||
|
points.waistLeft = points.topRight.shiftFractionTowards(
|
||||||
|
points.frontPocketStart,
|
||||||
|
options.frontAttachmentWidth
|
||||||
|
)
|
||||||
|
points.waistRight = points.frontPocketStart.shiftFractionTowards(points.topRight, 0.95)
|
||||||
|
points.foldLeft = new Point(points.waistLeft.x, points.trueBottomRight.y)
|
||||||
|
points.foldRight = new Point(points.waistRight.x, points.foldLeft.y)
|
||||||
|
points.edgeLeft = points.foldLeft.shift(-90, points.foldLeft.y - points.frontPocketSide.y / 2)
|
||||||
|
points.edgeRight = new Point(points.waistRight.x, points.edgeLeft.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indicate the chamfers and fold line
|
||||||
|
*/
|
||||||
|
points.chamferLeft = points.foldLeft.shiftFractionTowards(
|
||||||
|
points.foldRight,
|
||||||
|
options.frontAttachmentChamferSize
|
||||||
|
)
|
||||||
|
points.chamferRight = points.foldRight.shiftFractionTowards(
|
||||||
|
points.foldLeft,
|
||||||
|
options.frontAttachmentChamferSize
|
||||||
|
)
|
||||||
|
points.chamferLeftTop = points.chamferLeft.rotate(90, points.foldLeft)
|
||||||
|
points.chamferLeftBottom = points.chamferLeft.rotate(-90, points.foldLeft)
|
||||||
|
points.chamferRightTop = new Point(points.foldRight.x, points.chamferLeftTop.y)
|
||||||
|
points.chamferRightBottom = new Point(points.foldRight.x, points.chamferLeftBottom.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.waistLeft)
|
||||||
|
.line(points.edgeLeft)
|
||||||
|
.line(points.edgeRight)
|
||||||
|
.line(points.waistRight)
|
||||||
|
.line(points.waistLeft)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when it's requested.
|
||||||
|
* This also adds extra SA to fold under the edge.
|
||||||
|
*/
|
||||||
|
if (sa)
|
||||||
|
paths.sa = new Path()
|
||||||
|
.move(points.edgeRight)
|
||||||
|
.line(points.waistRight)
|
||||||
|
.line(points.waistLeft)
|
||||||
|
.line(points.edgeLeft)
|
||||||
|
.offset(sa)
|
||||||
|
.join(
|
||||||
|
new Path()
|
||||||
|
.move(points.edgeLeft)
|
||||||
|
.line(points.edgeRight)
|
||||||
|
.offset(3 * sa)
|
||||||
|
)
|
||||||
|
.close()
|
||||||
|
.attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user wants a complete pattern, let's add some more guidance
|
||||||
|
*/
|
||||||
|
if (complete) {
|
||||||
|
/*
|
||||||
|
* Add the fold line
|
||||||
|
*/
|
||||||
|
paths.fold = new Path().move(points.foldLeft).line(points.foldRight).addClass('help note')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the chamfers (the 45-degree slant at the corners of the fold)
|
||||||
|
*/
|
||||||
|
paths.chamfer = new Path()
|
||||||
|
.move(points.chamferLeftTop)
|
||||||
|
.line(points.chamferLeft)
|
||||||
|
.line(points.chamferLeftBottom)
|
||||||
|
.move(points.chamferRightTop)
|
||||||
|
.line(points.chamferRight)
|
||||||
|
.line(points.chamferRightBottom)
|
||||||
|
.addClass('note dashed stroke-sm')
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up a bit
|
||||||
|
*/
|
||||||
|
delete paths.corner
|
||||||
|
delete paths.hem
|
||||||
|
delete paths.side
|
||||||
|
delete paths.frontWaist
|
||||||
|
delete paths.pocketbag
|
||||||
|
delete paths.pocketbagBoundary
|
||||||
|
delete paths.pocketfacingBoundary
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.foldLeft
|
||||||
|
.shiftFractionTowards(points.foldRight, 0.2)
|
||||||
|
.shift(90, points.foldLeft.y / 2)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 8,
|
||||||
|
title: 'frontAttachment',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the logo
|
||||||
|
*/
|
||||||
|
points.logo = points.title.shift(-70, 70)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a 'fold here' note
|
||||||
|
*/
|
||||||
|
macro('banner', {
|
||||||
|
path: paths.fold,
|
||||||
|
text: 'foldHere',
|
||||||
|
className: 'text-sm fill-note',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sprinkle some notches
|
||||||
|
*/
|
||||||
|
macro('sprinkle', {
|
||||||
|
snippet: 'notch',
|
||||||
|
on: [
|
||||||
|
'chamferLeftTop',
|
||||||
|
'chamferLeftBottom',
|
||||||
|
'chamferLeft',
|
||||||
|
'chamferRightTop',
|
||||||
|
'chamferRightBottom',
|
||||||
|
'chamferRight',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'width',
|
||||||
|
from: points.edgeLeft,
|
||||||
|
to: points.edgeRight,
|
||||||
|
y: points.edgeLeft.y + 3 * sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'chamferWidth',
|
||||||
|
from: points.foldLeft,
|
||||||
|
to: points.chamferLeft,
|
||||||
|
y: points.chamferLeftBottom.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'chamferHeight',
|
||||||
|
from: points.chamferLeftBottom,
|
||||||
|
to: points.chamferLeft,
|
||||||
|
x: points.chamferLeft.x + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'bottomLength',
|
||||||
|
from: points.edgeRight,
|
||||||
|
to: points.foldRight,
|
||||||
|
x: points.edgeRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'topLength',
|
||||||
|
from: points.foldRight,
|
||||||
|
to: points.waistRight,
|
||||||
|
x: points.edgeRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'length',
|
||||||
|
from: points.edgeRight,
|
||||||
|
to: points.waistRight,
|
||||||
|
x: points.edgeRight.x + sa + 30,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
346
designs/naomiwu/src/front-base.mjs
Normal file
346
designs/naomiwu/src/front-base.mjs
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
import { back } from './back.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const frontBase = {
|
||||||
|
name: 'naomiwu.frontBase', // The name in design::part format
|
||||||
|
draft: draftFrontBase, // The method to call to draft this part
|
||||||
|
hide: { self: true }, // This part is hidden by default
|
||||||
|
after: back, // Draw the (imported) back part prior to drafting this part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper method to find a point on the (potentially curved) waistline for a
|
||||||
|
* given X coordinate
|
||||||
|
*
|
||||||
|
* @param {x} number - The X-coordinate to find the intersection with the waist
|
||||||
|
* for
|
||||||
|
* @return {point} Point - A Point object that lies at the intersection of the
|
||||||
|
* waist with x
|
||||||
|
*/
|
||||||
|
export const xOnWaist = (x, part) => {
|
||||||
|
const { options, utils, points, Point } = part.shorthand()
|
||||||
|
|
||||||
|
return options.waistSlant
|
||||||
|
? utils.curveIntersectsX(points.topLeft, points.topCp, points.topRight, points.topRight, x)
|
||||||
|
: new Point(x, points.topLeft.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper method to draw the corner of the front where the pocket goes
|
||||||
|
*
|
||||||
|
* This is abstracted into a method because we need to draft two fronts that
|
||||||
|
* are mirror images of one another. If we mirror them, the entire path will be
|
||||||
|
* mirrored, including text and so on. So this method allows us to mirror
|
||||||
|
* first, then call this method again to draw the non-mirrored path using the
|
||||||
|
* mirrored points, which is what we want.
|
||||||
|
*
|
||||||
|
* @param {part} Part - The current part object
|
||||||
|
*
|
||||||
|
* @return {path} Path - The path object that was drawn
|
||||||
|
*/
|
||||||
|
export const drawCornerPath = (part) => {
|
||||||
|
const { Path, points, paths } = part.shorthand()
|
||||||
|
|
||||||
|
return new Path()
|
||||||
|
.move(points.frontPocketSide)
|
||||||
|
.line(points.topRight)
|
||||||
|
.join(paths.frontWaistSide)
|
||||||
|
.addClass('note dashed stroke-sm')
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper method to draw the corner of the front where the pocket goes
|
||||||
|
*
|
||||||
|
* This is abstracted into a method because we need to draft two fronts that
|
||||||
|
* are mirror images of one another. If we mirror them, the entire path will be
|
||||||
|
* mirrored, including text and so on. So this method allows us to mirror
|
||||||
|
* first, then call this method again to draw the non-mirrored path using the
|
||||||
|
* mirrored points, which is what we want.
|
||||||
|
*
|
||||||
|
* @param {part} Part - The current part object
|
||||||
|
*
|
||||||
|
* @return {path} Path - The path object that was drawn
|
||||||
|
*/
|
||||||
|
export const drawSeamLine = (part) => {
|
||||||
|
const { Path, points, paths } = part.shorthand()
|
||||||
|
|
||||||
|
return new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.trueBottomRight)
|
||||||
|
.line(points.frontPocketSide)
|
||||||
|
.line(points.frontPocketCurveStart)
|
||||||
|
.curve(points.frontPocketCpSide, points.frontPocketCpTop, points.frontPocketStart)
|
||||||
|
.join(paths.frontWaistCenter)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper method to draw a note on the side seam
|
||||||
|
*
|
||||||
|
* This is abstracted into a method because we need to draft two fronts that
|
||||||
|
* are mirror images of one another. If we mirror them, the entire path will be
|
||||||
|
* mirrored, including text and so on. So this method allows us to mirror
|
||||||
|
* first, then call this method again to draw the non-mirrored path using the
|
||||||
|
* mirrored points, which is what we want.
|
||||||
|
*
|
||||||
|
* @param {part} Part - The current part object
|
||||||
|
*
|
||||||
|
* @return {path} Path - The path object that was drawn
|
||||||
|
*/
|
||||||
|
export const drawSideNote = (part) => {
|
||||||
|
const { Path, points } = part.shorthand()
|
||||||
|
|
||||||
|
return new Path()
|
||||||
|
.move(points.trueBottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
.addClass('hidden')
|
||||||
|
.addText('sideSeam', 'center fill-note text-sm')
|
||||||
|
.attr('data-text-dy', -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper method to draw a note on the hem seam
|
||||||
|
*
|
||||||
|
* This is abstracted into a method because we need to draft two fronts that
|
||||||
|
* are mirror images of one another. If we mirror them, the entire path will be
|
||||||
|
* mirrored, including text and so on. So this method allows us to mirror
|
||||||
|
* first, then call this method again to draw the non-mirrored path using the
|
||||||
|
* mirrored points, which is what we want.
|
||||||
|
*
|
||||||
|
* @param {part} Part - The current part object
|
||||||
|
*
|
||||||
|
* @return {path} Path - The path object that was drawn
|
||||||
|
*/
|
||||||
|
export const drawHemNote = (part) => {
|
||||||
|
const { Path, points } = part.shorthand()
|
||||||
|
|
||||||
|
return new Path()
|
||||||
|
.move(points.bottomLeft)
|
||||||
|
.line(points.trueBottomRight)
|
||||||
|
.addClass('hidden')
|
||||||
|
.addText('hem', 'center fill-note text-sm')
|
||||||
|
.attr('data-text-dy', -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper method to draw a the pocket outline
|
||||||
|
*
|
||||||
|
* This is abstracted into a method because we need to draft two fronts that
|
||||||
|
* are mirror images of one another. If we mirror them, the entire path will be
|
||||||
|
* mirrored, including text and so on. So this method allows us to mirror
|
||||||
|
* first, then call this method again to draw the non-mirrored path using the
|
||||||
|
* mirrored points, which is what we want.
|
||||||
|
*
|
||||||
|
* @param {part} Part - The current part object
|
||||||
|
* @param {reverse} bool - Indicates whether we are drawing the reversed version or not
|
||||||
|
*
|
||||||
|
* @return {path} Path - The path object that was drawn
|
||||||
|
*/
|
||||||
|
export const drawPocketBag = (part, reverse) => {
|
||||||
|
const { paths, Path, points } = part.shorthand()
|
||||||
|
|
||||||
|
paths.pocketbag = new Path()
|
||||||
|
.move(points.frontPocketBagStart)
|
||||||
|
.line(points.frontPocketBagHem)
|
||||||
|
.addClass('note dashed stroke-sm')
|
||||||
|
paths.pocketfacingBoundary = new Path()
|
||||||
|
.move(reverse ? points.frontPocketFacingSide : points.frontPocketFacingCenter)
|
||||||
|
.line(reverse ? points.frontPocketFacingCenter : points.frontPocketFacingSide)
|
||||||
|
.addClass('note dashed stroke-sm')
|
||||||
|
.addText('pocketFacing', 'fill-note center text-sm')
|
||||||
|
paths.pocketbagBoundary = new Path()
|
||||||
|
.move(reverse ? points.frontPocketFacingSide : points.frontPocketFacingCenter)
|
||||||
|
.line(reverse ? points.frontPocketFacingCenter : points.frontPocketFacingSide)
|
||||||
|
.addClass('hidden')
|
||||||
|
.addText('pocketBag', 'fill-note center text-sm')
|
||||||
|
.attr('data-text-dy', 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper method to split the front waist at the point the pocket cutout starts
|
||||||
|
*
|
||||||
|
* Does not return, but mutates the part object
|
||||||
|
*
|
||||||
|
* @param {part} Part - The current part object
|
||||||
|
*/
|
||||||
|
export const splitFrontWaist = (part) => {
|
||||||
|
const { paths, points, Path, options } = part.shorthand()
|
||||||
|
// Handle the split of the waitline at the pocket openinig
|
||||||
|
paths.frontWaist = new Path().move(points.topRight)
|
||||||
|
if (options.waistSlant) paths.frontWaist.curve(points.topRight, points.topCp, points.topLeft)
|
||||||
|
else paths.frontWaist.line(points.topLeft)
|
||||||
|
paths.frontWaist.addClass('hidden')
|
||||||
|
|
||||||
|
// Store both halves for re-use
|
||||||
|
const halves = paths.frontWaist.split(part.points.frontPocketStart)
|
||||||
|
paths.frontWaistSide = halves[0].hide()
|
||||||
|
paths.frontWaistCenter = halves[1].hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the back panel of the skirt
|
||||||
|
*/
|
||||||
|
function draftFrontBase({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
options,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
absoluteOptions,
|
||||||
|
utils,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* How much shaping should we add in the panel?
|
||||||
|
*/
|
||||||
|
const shaping = store.get('hipsQuarterReduction')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple skirt outline for the front panel
|
||||||
|
*/
|
||||||
|
points.topLeft = new Point(shaping / 2, 0)
|
||||||
|
points.topCp = new Point(store.get('frontQuarterHips') / 2, 0)
|
||||||
|
points.topRight = new Point(
|
||||||
|
points.topLeft.x + store.get('frontQuarterHips'),
|
||||||
|
absoluteOptions.waistSlant * -1
|
||||||
|
)
|
||||||
|
points.bottomLeft = new Point(0, points.topRight.y + absoluteOptions.length)
|
||||||
|
points.bottomRight = new Point(store.get('frontQuarterSeat'), points.bottomLeft.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store the waist length so we can accurately notch the waistband
|
||||||
|
*/
|
||||||
|
store.set(
|
||||||
|
'frontHipLength',
|
||||||
|
options.waistSlant
|
||||||
|
? new Path().move(points.topLeft).curve_(points.topCp, points.topRight).length()
|
||||||
|
: points.topLeft.dx(points.topRight)
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* True the side seam
|
||||||
|
*/
|
||||||
|
points.trueBottomRight = points.topRight.shiftTowards(points.bottomRight, store.get('sideSeam'))
|
||||||
|
points.trueBottomLeft = new Point(0, points.trueBottomRight.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct the fly J-seam - see paths.jseam
|
||||||
|
*/
|
||||||
|
points.jseamTop = xOnWaist(points.topLeft.x + absoluteOptions.flyWidth, part)
|
||||||
|
points.jseamBottom = points.topLeft.shiftTowards(points.bottomLeft, absoluteOptions.flyLength)
|
||||||
|
points.jseamCorner = points.jseamBottom
|
||||||
|
.shiftTowards(points.topLeft, absoluteOptions.flyWidth)
|
||||||
|
.rotate(-90, points.jseamBottom)
|
||||||
|
points.jseamCurveStart = points.jseamCorner.shiftTowards(
|
||||||
|
points.jseamTop,
|
||||||
|
absoluteOptions.flyWidth
|
||||||
|
)
|
||||||
|
points.jseamCpTop = points.jseamCorner.shiftFractionTowards(
|
||||||
|
points.jseamCurveStart,
|
||||||
|
1 - options.jseamBend
|
||||||
|
)
|
||||||
|
points.jseamCpBottom = points.jseamCorner.shiftFractionTowards(
|
||||||
|
points.jseamBottom,
|
||||||
|
1 - options.jseamBend
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct the fly extention (fe) - see paths.seam
|
||||||
|
*/
|
||||||
|
macro('mirror', {
|
||||||
|
clone: true,
|
||||||
|
mirror: [points.jseamBottom, points.topLeft],
|
||||||
|
points: [
|
||||||
|
'jseamTop',
|
||||||
|
'jseamBottom',
|
||||||
|
'jseamCorner',
|
||||||
|
'jseamCurveStart',
|
||||||
|
'jseamCpTop',
|
||||||
|
'jseamCpBottom',
|
||||||
|
],
|
||||||
|
nameFormat: (name) => `${name}Fe`, //Fe = Fly extension
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct the front pocket cutout
|
||||||
|
*/
|
||||||
|
points.frontPocketStart = xOnWaist(absoluteOptions.frontPocketOpeningWidth, part)
|
||||||
|
points.frontPocketSide = utils.beamIntersectsY(
|
||||||
|
points.topRight,
|
||||||
|
points.trueBottomRight,
|
||||||
|
absoluteOptions.frontPocketOpeningDepth
|
||||||
|
)
|
||||||
|
points.frontPocketCorner = new Point(points.frontPocketStart.x, points.frontPocketSide.y)
|
||||||
|
points.frontPocketCurveStart = points.frontPocketStart.rotate(-90, points.frontPocketCorner)
|
||||||
|
points.frontPocketCpTop = points.frontPocketCorner.shiftFractionTowards(
|
||||||
|
points.frontPocketStart,
|
||||||
|
1 - options.frontPocketOpeningBend
|
||||||
|
)
|
||||||
|
points.frontPocketCpSide = points.frontPocketCorner.shiftFractionTowards(
|
||||||
|
points.frontPocketCurveStart,
|
||||||
|
1 - options.frontPocketOpeningBend
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Front pocket bag/facing outline
|
||||||
|
*/
|
||||||
|
points.frontPocketBagStart = points.frontPocketStart.shiftFractionTowards(points.jseamTop, 0.4)
|
||||||
|
points.frontPocketBagHem = new Point(points.frontPocketBagStart.x, points.bottomRight.y)
|
||||||
|
points.frontPocketFacingSide = points.frontPocketSide.shiftFractionTowards(points.topRight, -0.4)
|
||||||
|
points.frontPocketFacingCenter = new Point(
|
||||||
|
points.frontPocketBagStart.x,
|
||||||
|
points.frontPocketFacingSide.y
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Paths
|
||||||
|
*/
|
||||||
|
splitFrontWaist(part) // Handle the split of the waitline at the pocket openinig
|
||||||
|
paths.seam = drawSeamLine(part) // Seamline
|
||||||
|
|
||||||
|
// Complete?
|
||||||
|
if (complete) {
|
||||||
|
/*
|
||||||
|
* Add the logo
|
||||||
|
*/
|
||||||
|
points.logo = points.topLeft
|
||||||
|
.shiftFractionTowards(points.bottomLeft, 0.3)
|
||||||
|
.shift(0, points.topRight.x / 3)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.logo.shift(-90, 70)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: '0',
|
||||||
|
title: 'frontBase',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add various helper paths
|
||||||
|
*/
|
||||||
|
paths.corner = drawCornerPath(part) // Pocket corner
|
||||||
|
drawPocketBag(part) // Pocket bag
|
||||||
|
paths.side = drawSideNote(part) // Note on side seam
|
||||||
|
paths.hem = drawHemNote(part) // Note on hem
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add seam allowance only if requested
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
}
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
252
designs/naomiwu/src/front-fly-side.mjs
Normal file
252
designs/naomiwu/src/front-fly-side.mjs
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
import {
|
||||||
|
frontBase,
|
||||||
|
splitFrontWaist,
|
||||||
|
drawCornerPath,
|
||||||
|
drawSideNote,
|
||||||
|
drawHemNote,
|
||||||
|
drawPocketBag,
|
||||||
|
} from './front-base.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const frontFlySide = {
|
||||||
|
name: 'naomiwu.frontFlySide', // Name in design::part format
|
||||||
|
draft: draftFrontFlySide, // Method to call to draft this part
|
||||||
|
from: frontBase, // Draft this part starting from (the imported) frontBase
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the front panel of the skirt with the fly on it
|
||||||
|
* Whether that ends up being the right or left panel depends on the
|
||||||
|
* 'invertFly' option.
|
||||||
|
* By default, this is the left panel, if the option is truthy, this becomes
|
||||||
|
* the right panel.
|
||||||
|
*
|
||||||
|
* Basic outline was drafted in frontBase
|
||||||
|
*
|
||||||
|
* Note that Left/Right is always from the vantage point the wearer
|
||||||
|
*/
|
||||||
|
function draftFrontFlySide({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
options,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
paperless,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* If the user wants the fly side inverted, we should mirror the entire thing
|
||||||
|
*/
|
||||||
|
if (options.invertFly) {
|
||||||
|
for (const p in points) points[p] = points[p].flipX()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to re-split the waist after mirroring
|
||||||
|
*/
|
||||||
|
splitFrontWaist(part)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store the J-Seam dimensions to construct the fly shield later
|
||||||
|
*/
|
||||||
|
store.set('jseamWidth', points.jseamCorner.x)
|
||||||
|
store.set('jseamHeight', points.jseamCorner.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Seamline
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.topLeft)
|
||||||
|
.line(points.jseamTopFe)
|
||||||
|
.line(points.jseamCurveStartFe)
|
||||||
|
.curve(points.jseamCpTopFe, points.jseamCpBottomFe, points.jseamBottomFe)
|
||||||
|
.line(points.bottomLeft)
|
||||||
|
.line(points.trueBottomRight)
|
||||||
|
.line(points.frontPocketSide)
|
||||||
|
.line(points.frontPocketCurveStart)
|
||||||
|
.curve(points.frontPocketCpSide, points.frontPocketCpTop, points.frontPocketStart)
|
||||||
|
.join(paths.frontWaistCenter)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Seam allowance. Only if the user wants it.
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user wants a complete pattern, let's add some more guidance
|
||||||
|
*/
|
||||||
|
if (complete) {
|
||||||
|
/*
|
||||||
|
* The J-Seam
|
||||||
|
*/
|
||||||
|
paths.jseam = new Path()
|
||||||
|
.move(points.jseamBottom)
|
||||||
|
.curve(points.jseamCpBottom, points.jseamCpTop, points.jseamCurveStart)
|
||||||
|
.line(points.jseamTop)
|
||||||
|
.addClass('note dashed stroke-sm')
|
||||||
|
.addText('jSeam', 'text-sm center fill-note')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The fly fold line
|
||||||
|
*/
|
||||||
|
paths.flyFold = new Path()
|
||||||
|
.move(points.jseamBottom)
|
||||||
|
.line(points.topLeft)
|
||||||
|
.addClass('note help stroke-sm')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a 'fold here' note along the fold line
|
||||||
|
*/
|
||||||
|
macro('banner', {
|
||||||
|
path: paths.flyFold,
|
||||||
|
text: 'foldHere',
|
||||||
|
className: 'text-sm fill-note',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add various helper paths
|
||||||
|
*/
|
||||||
|
paths.corner = drawCornerPath(part) // Pocket corner
|
||||||
|
drawPocketBag(part) // Pocket bag
|
||||||
|
paths.side = drawSideNote(part) // Note on side seam
|
||||||
|
paths.hem = drawHemNote(part) // Note on hem
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a grainline indicator
|
||||||
|
*/
|
||||||
|
points.grainlineTop = points.jseamTop.shiftFractionTowards(points.topLeft, 0.5)
|
||||||
|
points.grainlineBottom = new Point(points.grainlineTop.x, points.bottomLeft.y)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove title from frontBase and add our own title
|
||||||
|
*/
|
||||||
|
macro('rmtitle')
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 2,
|
||||||
|
title: options.invertFly ? 'frontFlySideRight' : 'frontFlySideLeft',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overwrite logo from frontBase to add our own logo in the place we want
|
||||||
|
*/
|
||||||
|
points.logo = points.frontPocketCurveStart.shiftFractionTowards(points.bottomRight, 0.5)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add notches
|
||||||
|
*/
|
||||||
|
macro('sprinkle', {
|
||||||
|
snippet: 'notch',
|
||||||
|
on: ['jseamTop', 'frontPocketBagStart', 'topLeft', 'jseamBottomFe'],
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add dimentions for paperless only when needed
|
||||||
|
*/
|
||||||
|
if (paperless) {
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wFlyExtension',
|
||||||
|
from: points.jseamTopFe,
|
||||||
|
to: points.topLeft,
|
||||||
|
y: points.jseamTopFe.y - sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wFly',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.jseamTop,
|
||||||
|
y: points.jseamTopFe.y - sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wCfrontToPocket',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.frontPocketStart,
|
||||||
|
y: points.jseamTopFe.y - sa - 30,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wCfrontToFlyExtensionBottom',
|
||||||
|
from: points.jseamCurveStartFe,
|
||||||
|
to: points.topLeft,
|
||||||
|
y: points.jseamTopFe.y - sa - 30,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wCfrontToSideWaist',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.topRight,
|
||||||
|
y: points.jseamTopFe.y - sa - 45,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wCfrontToSidePocket',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.frontPocketSide,
|
||||||
|
y: points.jseamTopFe.y - sa - 60,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wCfrontToSieHem',
|
||||||
|
from: points.topLeft,
|
||||||
|
to: points.trueBottomRight,
|
||||||
|
y: points.jseamTopFe.y - sa - 75,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wCfBottomToSidePocket',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.frontPocketSide,
|
||||||
|
y: points.bottomLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wCfBottomToSideHem',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.trueBottomRight,
|
||||||
|
y: points.bottomLeft.y + sa + 30,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wFull',
|
||||||
|
from: points.jseamCurveStartFe,
|
||||||
|
to: points.trueBottomRight,
|
||||||
|
y: points.bottomLeft.y + sa + 45,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hSideHemToPocket',
|
||||||
|
from: points.trueBottomRight,
|
||||||
|
to: points.frontPocketSide,
|
||||||
|
x: points.trueBottomRight.x + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hSideHemToWaist',
|
||||||
|
from: points.trueBottomRight,
|
||||||
|
to: points.frontPocketStart,
|
||||||
|
x: points.trueBottomRight.x + sa + 30,
|
||||||
|
})
|
||||||
|
if (options.waistSlant) {
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hFullWithSlant',
|
||||||
|
from: points.trueBottomRight,
|
||||||
|
to: points.topRight,
|
||||||
|
x: points.trueBottomRight.x + sa + 45,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
201
designs/naomiwu/src/front-nofly-side.mjs
Normal file
201
designs/naomiwu/src/front-nofly-side.mjs
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
import {
|
||||||
|
frontBase,
|
||||||
|
splitFrontWaist,
|
||||||
|
drawCornerPath,
|
||||||
|
drawSeamLine,
|
||||||
|
drawSideNote,
|
||||||
|
drawHemNote,
|
||||||
|
drawPocketBag,
|
||||||
|
} from './front-base.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This function drafts the front panel of the skirt without the fly on it
|
||||||
|
* Whether that ends up being the right or left panel depends on the
|
||||||
|
* 'invertFly' option.
|
||||||
|
* By default, this is the right panel, if the option is truthy, this becomes
|
||||||
|
* the right panel.
|
||||||
|
*
|
||||||
|
* Basic outline was drafted in frontBase
|
||||||
|
*
|
||||||
|
* Note that Left/Right is always from the vantage point the wearer
|
||||||
|
*/
|
||||||
|
export const frontNoFlySide = {
|
||||||
|
name: 'naomiwu.frontNoFlySide', // Name in design:part format
|
||||||
|
draft: draftFrontNoFlySide, // Method to call to draft this part
|
||||||
|
from: frontBase, // Draft this starting from (the imported) frontBase part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the right front panel of the skirt
|
||||||
|
*
|
||||||
|
* Basic outline was drafted in frontBase
|
||||||
|
* Now we adapt it for the right panel
|
||||||
|
*
|
||||||
|
* Note that Left/Right is always from the vantage point the wearer
|
||||||
|
*/
|
||||||
|
function draftFrontNoFlySide({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
options,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* Let's mirror the entire thing, unless the user wants the fly side inverted
|
||||||
|
* In that case, we already have it the way it should be.
|
||||||
|
*/
|
||||||
|
if (!options.invertFly) {
|
||||||
|
for (const p in points) points[p] = points[p].flipX()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to re-split the waist after mirroring it and re-draw paths
|
||||||
|
*/
|
||||||
|
splitFrontWaist(part)
|
||||||
|
paths.corner = drawCornerPath(part) // Corner
|
||||||
|
paths.seam = drawSeamLine(part) // Seamline
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA if it's requested
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(-1 * sa).attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user wants a complete pattern, let's add some more guidance
|
||||||
|
*/
|
||||||
|
if (complete) {
|
||||||
|
/*
|
||||||
|
* Draw various helper paths
|
||||||
|
*/
|
||||||
|
drawPocketBag(part, true) // Pocket bage
|
||||||
|
paths.side = drawSideNote(part) // Helper note on the side seam
|
||||||
|
paths.hem = drawHemNote(part).reverse(true) // Helper note on the hem
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overwrite title from frontBase to add our own title
|
||||||
|
*/
|
||||||
|
macro('rmtitle')
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 3,
|
||||||
|
title: options.invertFly ? 'frontNoFlySideLeft' : 'frontNoFlySideRight',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the 1 notch that is on this part
|
||||||
|
*/
|
||||||
|
snippets.notch = new Snippet('notch', points.frontPocketBagStart)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a grainline indicator
|
||||||
|
*/
|
||||||
|
points.grainlineTop = points.topLeft.shiftFractionTowards(points.jseamTop, 0.5)
|
||||||
|
points.grainlineBottom = new Point(points.grainlineTop.x, points.bottomLeft.y)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overwrite logo from frontBase to add our own (or rather the same in our preferred location)
|
||||||
|
*/
|
||||||
|
points.logo = points.topLeft.shiftFractionTowards(points.bottomRight, 0.5)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wAtHem',
|
||||||
|
from: points.trueBottomRight,
|
||||||
|
to: points.bottomLeft,
|
||||||
|
y: points.bottomLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wPocketNotchToCfront',
|
||||||
|
from: points.frontPocketBagStart,
|
||||||
|
to: points.topLeft,
|
||||||
|
y: points.frontPocketStart.y - sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wPocketCutoutToCfront',
|
||||||
|
from: points.frontPocketStart,
|
||||||
|
to: points.topLeft,
|
||||||
|
y: points.frontPocketStart.y - sa - 30,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wPocketCutout',
|
||||||
|
from: points.frontPocketSide,
|
||||||
|
to: points.frontPocketStart,
|
||||||
|
y: points.frontPocketStart.y - sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wPocketCutoutToCfHem',
|
||||||
|
from: points.frontPocketStart,
|
||||||
|
to: points.trueBottomLeft,
|
||||||
|
y: points.frontPocketStart.y - sa - 45,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wSideHemToStartPocketCutout',
|
||||||
|
from: points.trueBottomRight,
|
||||||
|
to: points.frontPocketStart,
|
||||||
|
y: points.frontPocketStart.y - sa - 30,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hSideHemToPocketCutout',
|
||||||
|
from: points.trueBottomRight,
|
||||||
|
to: points.frontPocketSide,
|
||||||
|
x: points.bottomRight.x - sa - 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hHemBottomToPocketCutout',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.frontPocketSide,
|
||||||
|
x: points.bottomRight.x - sa - 30,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hCfHemToPoketStart',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.frontPocketStart,
|
||||||
|
x: points.bottomRight.x - sa - 45,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
from: points.bottomLeft,
|
||||||
|
id: 'hTopLeftBottomLeft',
|
||||||
|
to: points.topLeft,
|
||||||
|
x: points.bottomLeft.x + sa + 15,
|
||||||
|
})
|
||||||
|
if (options.waistSlant) {
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hFullWithSlant',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.topRight,
|
||||||
|
x: points.bottomRight.x - sa - 60,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hWithSlantCfront',
|
||||||
|
from: points.bottomLeft,
|
||||||
|
to: points.frontPocketStart,
|
||||||
|
x: points.bottomLeft.x + sa + 30,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
111
designs/naomiwu/src/front-pocket-bag.mjs
Normal file
111
designs/naomiwu/src/front-pocket-bag.mjs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
import { frontBase } from './front-base.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const frontPocketBag = {
|
||||||
|
name: 'naomiwu.frontPocketBag', // The name in design::part format
|
||||||
|
draft: draftFrontPocketBag, // The method to call to draft this part
|
||||||
|
from: frontBase, // Draft this starting from the (imported) frontBase part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the front pocket bag of the skirt
|
||||||
|
*/
|
||||||
|
function draftFrontPocketBag({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
part,
|
||||||
|
store,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* Remove paths we don't need
|
||||||
|
*/
|
||||||
|
delete paths.corner
|
||||||
|
delete paths.hem
|
||||||
|
delete paths.frontWaist
|
||||||
|
delete paths.pocketbag
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.frontPocketBagStart)
|
||||||
|
.line(points.frontPocketBagHem)
|
||||||
|
.line(points.trueBottomRight)
|
||||||
|
.line(points.topRight)
|
||||||
|
.join(paths.frontWaistSide)
|
||||||
|
.line(points.frontPocketBagStart)
|
||||||
|
.close()
|
||||||
|
.addClass('various')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add SA only when requested
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 2, from: 'lining', onFold: true })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overwrite title from frontBase
|
||||||
|
*/
|
||||||
|
points.title = new Point(
|
||||||
|
points.frontPocketFacingCenter.x * 1.5,
|
||||||
|
points.frontPocketFacingCenter.y / 1.5
|
||||||
|
)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 5,
|
||||||
|
title: 'frontPocketBag',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overwrite logo from frontBase
|
||||||
|
*/
|
||||||
|
points.logo = points.title.shift(12, 100)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a cut-on-fold indicator
|
||||||
|
*/
|
||||||
|
macro('cutonfold', {
|
||||||
|
from: points.frontPocketBagStart,
|
||||||
|
to: points.frontPocketBagHem,
|
||||||
|
grainline: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wAtTop',
|
||||||
|
from: points.frontPocketBagStart,
|
||||||
|
to: points.topRight,
|
||||||
|
y: points.topLeft.y - sa - 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wAtBottom',
|
||||||
|
from: points.frontPocketBagHem,
|
||||||
|
to: points.bottomRight,
|
||||||
|
y: points.bottomLeft.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hFull',
|
||||||
|
from: points.frontPocketBagHem,
|
||||||
|
to: points.frontPocketBagStart,
|
||||||
|
x: points.frontPocketBagHem.x - sa - 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
100
designs/naomiwu/src/front-pocket-facing.mjs
Normal file
100
designs/naomiwu/src/front-pocket-facing.mjs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import { frontPocketBag } from './front-pocket-bag.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const frontPocketFacing = {
|
||||||
|
name: 'naomiwu.frontPocketFacing', // The name in design::part format
|
||||||
|
draft: draftFrontPocketFacing, // The method to call to draft this part
|
||||||
|
from: frontPocketBag, // Draft this starting from the (imported) frontPocketBag part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the front pocket facing of the skirt
|
||||||
|
*/
|
||||||
|
function draftFrontPocketFacing({ points, Path, paths, store, part, sa, macro }) {
|
||||||
|
/*
|
||||||
|
* Clean up what we don't need
|
||||||
|
*/
|
||||||
|
delete paths.pocketbagBoundary
|
||||||
|
delete paths.pocketfacingBoundary
|
||||||
|
macro('rmad') // Removes all dimensions
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The seam line
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.frontPocketBagStart)
|
||||||
|
.line(points.frontPocketFacingCenter)
|
||||||
|
.line(points.frontPocketFacingSide)
|
||||||
|
.line(points.topRight)
|
||||||
|
.join(paths.frontWaistSide)
|
||||||
|
.line(points.frontPocketBagStart)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when requested
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fix text alignement on the side seam
|
||||||
|
*/
|
||||||
|
paths.side = new Path()
|
||||||
|
.move(points.frontPocketFacingSide)
|
||||||
|
.line(points.topRight)
|
||||||
|
.addClass('hidden')
|
||||||
|
.addText('sideSeam', 'center fill-note text-sm')
|
||||||
|
.attr('data-text-dy', -1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 2, from: 'fabric', onFold: true })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title ( and remove the inherited one)
|
||||||
|
*/
|
||||||
|
macro('rmtitle')
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 6,
|
||||||
|
title: 'frontPocketFacing',
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add cut-on-fold indicator
|
||||||
|
*/
|
||||||
|
macro('cutonfold', {
|
||||||
|
from: points.frontPocketBagStart,
|
||||||
|
to: points.frontPocketFacingCenter,
|
||||||
|
grainline: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wAtBottom',
|
||||||
|
from: points.frontPocketFacingCenter,
|
||||||
|
to: points.frontPocketFacingSide,
|
||||||
|
y: points.frontPocketFacingCenter.y + sa + 15,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'wAtTop',
|
||||||
|
from: points.frontPocketBagStart,
|
||||||
|
to: points.topRight,
|
||||||
|
y: points.topRight.y - sa - 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'hFull',
|
||||||
|
from: points.frontPocketFacingCenter,
|
||||||
|
to: points.frontPocketBagStart,
|
||||||
|
x: points.frontPocketFacingCenter.x - sa - 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
94
designs/naomiwu/src/index.mjs
Normal file
94
designs/naomiwu/src/index.mjs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import { Design } from '@freesewing/core'
|
||||||
|
import { data } from '../data.mjs'
|
||||||
|
import { i18n } from '../i18n/index.mjs'
|
||||||
|
// Parts
|
||||||
|
import { shared } from './shared.mjs'
|
||||||
|
import { back } from './back.mjs'
|
||||||
|
import { frontBase } from './front-base.mjs'
|
||||||
|
import { frontFlySide } from './front-fly-side.mjs'
|
||||||
|
import { frontNoFlySide } from './front-nofly-side.mjs'
|
||||||
|
import { waistband } from './waistband.mjs'
|
||||||
|
import { flyShield } from './fly-shield.mjs'
|
||||||
|
import { frontPocketBag } from './front-pocket-bag.mjs'
|
||||||
|
import { frontPocketFacing } from './front-pocket-facing.mjs'
|
||||||
|
import { frontAttachment } from './front-attachment.mjs'
|
||||||
|
import { frontAttachmentFacing } from './front-attachment-facing.mjs'
|
||||||
|
import { backPocket } from './back-pocket.mjs'
|
||||||
|
import { backPocketFlap } from './back-pocket-flap.mjs'
|
||||||
|
import { backAttachmentBack } from './back-attachment-back.mjs'
|
||||||
|
import { backAttachmentFront } from './back-attachment-front.mjs'
|
||||||
|
import { backAttachmentFlap } from './back-attachment-flap.mjs'
|
||||||
|
import { beltLoop } from './belt-loop.mjs'
|
||||||
|
import { backBeltLoop } from './back-belt-loop.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create new design
|
||||||
|
*/
|
||||||
|
const Naomiwu = new Design({
|
||||||
|
data,
|
||||||
|
parts: [
|
||||||
|
shared,
|
||||||
|
back,
|
||||||
|
frontBase,
|
||||||
|
frontFlySide,
|
||||||
|
frontNoFlySide,
|
||||||
|
waistband,
|
||||||
|
flyShield,
|
||||||
|
frontPocketBag,
|
||||||
|
frontPocketFacing,
|
||||||
|
frontAttachment,
|
||||||
|
frontAttachmentFacing,
|
||||||
|
backPocket,
|
||||||
|
backPocketFlap,
|
||||||
|
backAttachmentBack,
|
||||||
|
backAttachmentFront,
|
||||||
|
backAttachmentFlap,
|
||||||
|
beltLoop,
|
||||||
|
backBeltLoop,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that we are creating this above as 'Naomiwu' and not 'NaomiWu', which
|
||||||
|
* would be the correctly camel-cased name of the person it's named after.
|
||||||
|
*
|
||||||
|
* The reason is that when discussing the name with Naomi, she originally
|
||||||
|
* suggested 'Open Cargo Skirt'. After explaining that we typically use
|
||||||
|
* first-names for our designs because we provide a website in multiple
|
||||||
|
* languages and want to have a name that does not need translation, she
|
||||||
|
* suggested either 'Wu Cargo Skirt' or 'Naomi Wu Cargo Skirt'.
|
||||||
|
*
|
||||||
|
* So we landed on 'Naomi Wu Cargo Skirt' which makes the short name of this
|
||||||
|
* pattern (as used in the NPM package and URLs) 'naomiwu'.
|
||||||
|
* To get the constructor from that, we capitalize the design name, so that
|
||||||
|
* is why 'Naomiwu' is exported.
|
||||||
|
*
|
||||||
|
* However, to be flexible, we also export this design as NaomiWu below.
|
||||||
|
* This way, both ways work.
|
||||||
|
*/
|
||||||
|
const NaomiWu = Naomiwu
|
||||||
|
|
||||||
|
// Named exports
|
||||||
|
export {
|
||||||
|
shared,
|
||||||
|
back,
|
||||||
|
frontBase,
|
||||||
|
frontFlySide,
|
||||||
|
frontNoFlySide,
|
||||||
|
waistband,
|
||||||
|
flyShield,
|
||||||
|
frontPocketBag,
|
||||||
|
frontPocketFacing,
|
||||||
|
frontAttachment,
|
||||||
|
frontAttachmentFacing,
|
||||||
|
backPocket,
|
||||||
|
backPocketFlap,
|
||||||
|
backAttachmentBack,
|
||||||
|
backAttachmentFront,
|
||||||
|
backAttachmentFlap,
|
||||||
|
beltLoop,
|
||||||
|
backBeltLoop,
|
||||||
|
Naomiwu,
|
||||||
|
NaomiWu, // See note above
|
||||||
|
i18n,
|
||||||
|
}
|
322
designs/naomiwu/src/shared.mjs
Normal file
322
designs/naomiwu/src/shared.mjs
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
import { pctBasedOn } from '@freesewing/core'
|
||||||
|
|
||||||
|
function draft({ store, measurements, options, part }) {
|
||||||
|
// Set values in the store for re-use
|
||||||
|
const hips = measurements.hips * (1 + options.hipsEase)
|
||||||
|
store.set('hips', hips)
|
||||||
|
store.set('frontQuarterHips', (hips * options.frontHalf) / 2)
|
||||||
|
store.set('backQuarterHips', (hips * (1 - options.frontHalf)) / 2)
|
||||||
|
const seat = measurements.seat * (1 + options.seatEase)
|
||||||
|
store.set('seat', seat)
|
||||||
|
store.set('frontQuarterSeat', (seat * options.frontHalf) / 2)
|
||||||
|
store.set('backQuarterSeat', (seat * (1 - options.frontHalf)) / 2)
|
||||||
|
store.set('hipsToSeat', measurements.waistToSeat - measurements.waistToHips)
|
||||||
|
store.set('hipsToUpperLeg', measurements.waistToUpperLeg - measurements.waistToHips)
|
||||||
|
store.set('seatToUpperLeg', measurements.waistToUpperLeg - measurements.waistToSeat)
|
||||||
|
// Never reduce a negative amount
|
||||||
|
const reduce = (seat - hips) / 4
|
||||||
|
store.set('hipsQuarterReduction', reduce > 0 ? reduce : 0)
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper method like pctBasedOn, but using quarter hips for measurement
|
||||||
|
*/
|
||||||
|
const pctBasedOnQhips = () => ({
|
||||||
|
toAbs: (value, { measurements }) => value * (measurements.hips / 4),
|
||||||
|
fromAbs: (value, { measurements }) => measurements.hips / 4 / value,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper method like pctBasedOn, but using hips to upperleg
|
||||||
|
*/
|
||||||
|
const pctBasedOnHipsToUleg = () => ({
|
||||||
|
toAbs: (value, { measurements }) =>
|
||||||
|
value * (measurements.waistToUpperLeg - measurements.waistToHips),
|
||||||
|
fromAbs: (value, { measurements }) =>
|
||||||
|
(measurements.waistToUpperLeg - measurements.waistToHips) / value,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const shared = {
|
||||||
|
name: 'naomiwu.shared',
|
||||||
|
measurements: ['hips', 'seat', 'waistToHips', 'waistToSeat', 'waistToUpperLeg'],
|
||||||
|
hide: { self: true },
|
||||||
|
options: {
|
||||||
|
// Fit options
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Amount of ease at the hips.
|
||||||
|
* By default this has no ease + elasticated waist (partially) because this
|
||||||
|
* is supposed to support cargo without sliding down. (belt is better, but still).
|
||||||
|
*/
|
||||||
|
hipsEase: {
|
||||||
|
pct: 0,
|
||||||
|
min: -5,
|
||||||
|
max: 5,
|
||||||
|
menu: 'fit',
|
||||||
|
...pctBasedOn('hips'),
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Amount of ease at the seat.
|
||||||
|
* Needs to be sufficient to allow dexterity but not so much that it's to flared
|
||||||
|
*/
|
||||||
|
seatEase: {
|
||||||
|
pct: 5,
|
||||||
|
min: 0,
|
||||||
|
max: 15,
|
||||||
|
menu: 'fit',
|
||||||
|
...pctBasedOn('seat'),
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How much the waist should slant downward at the front (and up at the back)
|
||||||
|
* This is based on a model with a perfectly horizontal waistline.
|
||||||
|
* However, people who -- as Sir Mix A Lot would say -- got (more) back benefit
|
||||||
|
* from a sloped waistline that raises up at teh back and dips lower at the front.
|
||||||
|
* This option facilitates that.
|
||||||
|
*/
|
||||||
|
waistSlant: {
|
||||||
|
pct: 0,
|
||||||
|
min: 0,
|
||||||
|
max: 2,
|
||||||
|
menu: 'fit',
|
||||||
|
...pctBasedOn('hips'),
|
||||||
|
},
|
||||||
|
|
||||||
|
// Style options
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allows one to swap the fly side for what is more convenient or best
|
||||||
|
* matches one's gender expression.
|
||||||
|
*
|
||||||
|
* This design is based ona physical skirt made/worn by Naomi Wu and that
|
||||||
|
* skirt had the traditional left-over-right fly that is the most common
|
||||||
|
* style used in all menswear but also often in womenswear bottoms.
|
||||||
|
*
|
||||||
|
* Changing this option will draft a right-over-left style which is common
|
||||||
|
* for womenswear tops and bottoms, and as such is more female-presenting.
|
||||||
|
*
|
||||||
|
* There's no right or wrong way, it's just preference. The reason
|
||||||
|
* left-over-right is the default here is because that's how it was on
|
||||||
|
* the skirt we based this on.
|
||||||
|
*/
|
||||||
|
invertFly: {
|
||||||
|
bool: false,
|
||||||
|
menu: 'style',
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The length as a percentage of the hips to upper leg measurements
|
||||||
|
*/
|
||||||
|
length: {
|
||||||
|
pct: 40,
|
||||||
|
min: 0,
|
||||||
|
max: 80,
|
||||||
|
menu: 'style',
|
||||||
|
toAbs: (value, { measurements }) =>
|
||||||
|
(1 + value) * (measurements.waistToUpperLeg - measurements.waistToHips),
|
||||||
|
fromAbs: (value, { measurements }) =>
|
||||||
|
(measurements.waistToUpperLeg - measurements.waistToHips) / (1 + value),
|
||||||
|
},
|
||||||
|
|
||||||
|
waistbandWidth: {
|
||||||
|
pct: 4.4,
|
||||||
|
min: 2,
|
||||||
|
max: 10,
|
||||||
|
menu: 'style',
|
||||||
|
...pctBasedOn('hips'),
|
||||||
|
},
|
||||||
|
|
||||||
|
beltLoopWidth: {
|
||||||
|
pct: 40,
|
||||||
|
min: 20,
|
||||||
|
max: 60,
|
||||||
|
menu: 'style',
|
||||||
|
toAbs: (value, { measurements }, mergedOptions) =>
|
||||||
|
value * measurements.hips * mergedOptions.waistbandWidth,
|
||||||
|
fromAbs: (value, { measurements }, mergedOptions) =>
|
||||||
|
(measurements.hips * mergedOptions.waistbandWidth) / value,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Pocket options
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Controls the curvature of the front pocket opening
|
||||||
|
*/
|
||||||
|
frontPocketOpeningBend: {
|
||||||
|
pct: 80,
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
menu: 'pockets',
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Controls the depth of the front pocket opening as a factor of
|
||||||
|
* waistToUpperLeg - waistToHip
|
||||||
|
*/
|
||||||
|
frontPocketOpeningDepth: {
|
||||||
|
pct: 33,
|
||||||
|
min: 25,
|
||||||
|
max: 45,
|
||||||
|
menu: 'pockets',
|
||||||
|
...pctBasedOnQhips(),
|
||||||
|
},
|
||||||
|
|
||||||
|
// Pocket options
|
||||||
|
backPocketDepth: {
|
||||||
|
pct: 70,
|
||||||
|
min: 60,
|
||||||
|
max: 85,
|
||||||
|
menu: 'pockets',
|
||||||
|
},
|
||||||
|
backPocketChamferSize: {
|
||||||
|
pct: 15,
|
||||||
|
min: 5,
|
||||||
|
max: 25,
|
||||||
|
menu: 'pockets',
|
||||||
|
},
|
||||||
|
frontPocketOpeningWidth: {
|
||||||
|
pct: 33,
|
||||||
|
min: 25,
|
||||||
|
max: 45,
|
||||||
|
menu: 'pockets',
|
||||||
|
...pctBasedOnQhips(),
|
||||||
|
},
|
||||||
|
|
||||||
|
// Width of the back attachment
|
||||||
|
backAttachmentWidth: {
|
||||||
|
pct: 40,
|
||||||
|
min: 25,
|
||||||
|
max: 55,
|
||||||
|
menu: 'pockets',
|
||||||
|
...pctBasedOnQhips(),
|
||||||
|
},
|
||||||
|
backAttachmentDepth: {
|
||||||
|
pct: 190,
|
||||||
|
min: 100,
|
||||||
|
max: 220,
|
||||||
|
menu: 'pockets',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Width of the front attachment
|
||||||
|
frontAttachmentWidth: {
|
||||||
|
pct: 95,
|
||||||
|
min: 80,
|
||||||
|
max: 110,
|
||||||
|
menu: 'pockets',
|
||||||
|
},
|
||||||
|
frontAttachmentChamferSize: {
|
||||||
|
pct: 15,
|
||||||
|
min: 5,
|
||||||
|
max: 25,
|
||||||
|
menu: 'pockets',
|
||||||
|
},
|
||||||
|
backAttachmentFlapChamferSize: {
|
||||||
|
pct: 15,
|
||||||
|
min: 5,
|
||||||
|
max: 25,
|
||||||
|
menu: 'pockets',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Advanced options
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dart length.
|
||||||
|
* Is a factor between the distance between the hipline and seatline
|
||||||
|
*/
|
||||||
|
dartLength: {
|
||||||
|
pct: 90,
|
||||||
|
min: 50,
|
||||||
|
max: 100,
|
||||||
|
menu: 'advanced',
|
||||||
|
toAbs: (value, { measurements }) =>
|
||||||
|
value * (measurements.waistToSeat - measurements.waistToHips),
|
||||||
|
fromAbs: (value, { measurements }) =>
|
||||||
|
(measurements.waistToSeat - measurements.waistToHips) / value,
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dart width.
|
||||||
|
* Doesn't influence fit, but rather determines how much shaping is done in the darts
|
||||||
|
*/
|
||||||
|
dartWidth: {
|
||||||
|
pct: 5,
|
||||||
|
min: 4,
|
||||||
|
max: 8,
|
||||||
|
menu: 'advanced',
|
||||||
|
...pctBasedOnQhips(),
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The fly length.
|
||||||
|
*/
|
||||||
|
flyLength: {
|
||||||
|
pct: 75,
|
||||||
|
min: 50,
|
||||||
|
max: 85,
|
||||||
|
menu: 'advanced',
|
||||||
|
...pctBasedOnHipsToUleg(),
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
* The fly width.
|
||||||
|
*/
|
||||||
|
flyWidth: {
|
||||||
|
pct: 16,
|
||||||
|
min: 10,
|
||||||
|
max: 22,
|
||||||
|
menu: 'advanced',
|
||||||
|
...pctBasedOnQhips(),
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Percentage of the full circumference that should be made up
|
||||||
|
* by the front panels. Increasing this will shift the side seams
|
||||||
|
* to the back, which increases space for the pockets. However if
|
||||||
|
* you shift them too far, the pocket opening sits too far to the
|
||||||
|
* side and becomes difficult to access. The default 60% is a good
|
||||||
|
* average.
|
||||||
|
*/
|
||||||
|
frontHalf: {
|
||||||
|
pct: 55,
|
||||||
|
min: 50,
|
||||||
|
max: 60,
|
||||||
|
menu: 'advanced',
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curvature of the J-Seam bend
|
||||||
|
*/
|
||||||
|
jseamBend: {
|
||||||
|
pct: 65,
|
||||||
|
min: 50,
|
||||||
|
max: 100,
|
||||||
|
menu: 'advanced',
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Minimal dart width. Below this width, we don't create darts but
|
||||||
|
* instead do all shaping in the side seams.
|
||||||
|
*/
|
||||||
|
minDartWidth: {
|
||||||
|
pct: 2,
|
||||||
|
min: 0.5,
|
||||||
|
max: 4,
|
||||||
|
menu: 'advanced',
|
||||||
|
toAbs: (pct, settings, mergedOptions) =>
|
||||||
|
(pct *
|
||||||
|
settings.measurements.hips *
|
||||||
|
(1 + mergedOptions.hipsEase) *
|
||||||
|
(1 - mergedOptions.frontHalf)) /
|
||||||
|
2,
|
||||||
|
fromAbs: (mm, settings) =>
|
||||||
|
(settings.measurements.hips *
|
||||||
|
(1 + settings.options.hipsEase) *
|
||||||
|
(1 - settings.options.frontHalf)) /
|
||||||
|
2 /
|
||||||
|
mm,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
draft: draft,
|
||||||
|
}
|
377
designs/naomiwu/src/waistband.mjs
Normal file
377
designs/naomiwu/src/waistband.mjs
Normal file
|
@ -0,0 +1,377 @@
|
||||||
|
import { frontBase } from './front-base.mjs'
|
||||||
|
import { capitalize } from '@freesewing/core'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the exported part object
|
||||||
|
*/
|
||||||
|
export const waistband = {
|
||||||
|
name: 'naomiwu.waistband', // The name in design::part format
|
||||||
|
draft: draftWaistband, // The method to call to draft this part
|
||||||
|
after: frontBase, // Draft this part starting from the (imported) frontBase part
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function drafts the waistband of the skirt
|
||||||
|
*/
|
||||||
|
function draftWaistband({
|
||||||
|
Point,
|
||||||
|
points,
|
||||||
|
Path,
|
||||||
|
paths,
|
||||||
|
store,
|
||||||
|
part,
|
||||||
|
options,
|
||||||
|
complete,
|
||||||
|
sa,
|
||||||
|
snippets,
|
||||||
|
Snippet,
|
||||||
|
macro,
|
||||||
|
absoluteOptions,
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
* We start from center back and make our way towards the front in both directions
|
||||||
|
*/
|
||||||
|
points.cbTop = new Point(0, 0)
|
||||||
|
points.cbBottom = new Point(points.cbTop.x, absoluteOptions.waistbandWidth * 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First add the back parts
|
||||||
|
*/
|
||||||
|
points.leftSideTop = points.cbTop.shift(180, store.get('backHipLength'))
|
||||||
|
points.leftSideBottom = new Point(points.leftSideTop.x, points.cbBottom.y)
|
||||||
|
points.rightSideTop = points.leftSideTop.flipX()
|
||||||
|
points.rightSideBottom = points.leftSideBottom.flipX()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now continue with the fronts
|
||||||
|
*/
|
||||||
|
points.leftFrontTop = points.leftSideTop.shift(180, store.get('frontHipLength'))
|
||||||
|
points.leftFrontBottom = new Point(points.leftFrontTop.x, points.cbBottom.y)
|
||||||
|
points.rightFrontTop = points.leftFrontTop.flipX()
|
||||||
|
points.rightFrontBottom = points.leftFrontBottom.flipX()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the overlap at the button side (noFly side)
|
||||||
|
*/
|
||||||
|
points.rightEdgeTop = points.rightFrontTop.shift(0, absoluteOptions.flyWidth)
|
||||||
|
points.rightEdgeBottom = new Point(points.rightEdgeTop.x, points.cbBottom.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fold in the middle
|
||||||
|
*/
|
||||||
|
points.midLeft = new Point(points.leftFrontTop.x, points.cbBottom.y / 2)
|
||||||
|
points.midRight = new Point(points.rightEdgeTop.x, points.midLeft.y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Location of the buttonhole (taking invertFly option into account)
|
||||||
|
*/
|
||||||
|
points.buttonhole = points.leftFrontBottom
|
||||||
|
.shiftFractionTowards(points.leftFrontTop, options.invertFly ? 0.75 : 0.25)
|
||||||
|
.shift(0, absoluteOptions.waistbandWidth / 4)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Location of the button
|
||||||
|
*/
|
||||||
|
points.button = new Point(
|
||||||
|
points.rightEdgeTop.x - absoluteOptions.flyWidth / 2,
|
||||||
|
points.buttonhole.y
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indicate the location of the belt loops
|
||||||
|
*/
|
||||||
|
points.leftBackLoopTop = points.cbTop.shiftFractionTowards(points.leftSideTop, 0.5)
|
||||||
|
points.leftSideLoopTop = points.leftSideTop.shiftFractionTowards(points.leftFrontTop, 0.06)
|
||||||
|
points.leftFrontLoopTop = points.leftSideTop.shiftFractionTowards(points.leftFrontTop, 0.53)
|
||||||
|
for (const key of ['Back', 'Side', 'Front']) {
|
||||||
|
points[`left${key}LoopBottom`] = new Point(points[`left${key}LoopTop`].x, points.cbBottom.y)
|
||||||
|
points[`right${key}LoopTop`] = points[`left${key}LoopTop`].flipX()
|
||||||
|
points[`right${key}LoopBottom`] = new Point(points[`right${key}LoopTop`].x, points.cbBottom.y)
|
||||||
|
/*
|
||||||
|
* Also add points on the left and right edge of the belt loop
|
||||||
|
* so we can draw the path later
|
||||||
|
*/
|
||||||
|
for (const side of ['left', 'right']) {
|
||||||
|
points[`${side}${key}LoopTopLeft`] = points[`${side}${key}LoopTop`].shift(
|
||||||
|
180,
|
||||||
|
absoluteOptions.beltLoopWidth / 2
|
||||||
|
)
|
||||||
|
points[`${side}${key}LoopTopRight`] = points[`${side}${key}LoopTop`].shift(
|
||||||
|
0,
|
||||||
|
absoluteOptions.beltLoopWidth / 2
|
||||||
|
)
|
||||||
|
points[`${side}${key}LoopBottomLeft`] = points[`${side}${key}LoopBottom`].shift(
|
||||||
|
180,
|
||||||
|
absoluteOptions.beltLoopWidth / 2
|
||||||
|
)
|
||||||
|
points[`${side}${key}LoopBottomRight`] = points[`${side}${key}LoopBottom`].shift(
|
||||||
|
0,
|
||||||
|
absoluteOptions.beltLoopWidth / 2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Center back belt loop is different (a large wide one)
|
||||||
|
*/
|
||||||
|
points.cbLoopTopLeft = points.cbTop.shiftFractionTowards(points.leftBackLoopTop, 0.5)
|
||||||
|
points.cbLoopTopRight = points.cbLoopTopLeft.flipX()
|
||||||
|
points.cbLoopBottomLeft = new Point(points.cbLoopTopLeft.x, points.cbBottom.y)
|
||||||
|
points.cbLoopBottomRight = points.cbLoopBottomLeft.flipX()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We want to add an attachment here that can hold a mobile phone
|
||||||
|
* However, we want to refrain from puttin it over any belt loops so let's
|
||||||
|
* see how wide it can be (max) and store that for re-use later when drafting
|
||||||
|
* the back attachment
|
||||||
|
*/
|
||||||
|
store.set('backAttachmentMaxWidth', points.leftSideLoopTopRight.dx(points.leftBackLoopTopLeft))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Seamline
|
||||||
|
*/
|
||||||
|
paths.seam = new Path()
|
||||||
|
.move(points.leftFrontTop)
|
||||||
|
.line(points.leftFrontBottom)
|
||||||
|
.line(points.rightEdgeBottom)
|
||||||
|
.line(points.rightEdgeTop)
|
||||||
|
.line(points.leftFrontTop)
|
||||||
|
.close()
|
||||||
|
.addClass('fabric')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add SA when requested
|
||||||
|
*/
|
||||||
|
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user wants a complete pattern, let's add some more guidance
|
||||||
|
*/
|
||||||
|
if (complete) {
|
||||||
|
/*
|
||||||
|
* Add the fold line
|
||||||
|
*/
|
||||||
|
paths.fold = new Path().move(points.midLeft).line(points.midRight).addClass('help note')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Include a message that this is where to fold the waistband
|
||||||
|
*/
|
||||||
|
macro('banner', {
|
||||||
|
path: paths.fold,
|
||||||
|
text: 'foldHere',
|
||||||
|
className: 'text-sm fill-note',
|
||||||
|
repeat: 50,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indicate the fly edge line
|
||||||
|
*/
|
||||||
|
paths.flyEdge = new Path()
|
||||||
|
.move(points.leftFrontBottom)
|
||||||
|
.line(points.leftFrontTop)
|
||||||
|
.addClass('note dashed')
|
||||||
|
.addText('flyEdge', 'text-sm fill-note center')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indicate location of the belt loops
|
||||||
|
*/
|
||||||
|
for (const key of ['Back', 'Side', 'Front']) {
|
||||||
|
for (const side of ['left', 'right']) {
|
||||||
|
paths[`beltLoop${capitalize(side)}${key}`] = new Path()
|
||||||
|
.move(points[`${side}${key}LoopTopLeft`])
|
||||||
|
.line(points[`${side}${key}LoopBottomLeft`])
|
||||||
|
.move(points[`${side}${key}LoopBottomRight`])
|
||||||
|
.line(points[`${side}${key}LoopTopRight`])
|
||||||
|
.addClass('note stroke-sm dashed')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cutlist
|
||||||
|
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the logo
|
||||||
|
*/
|
||||||
|
points.logo = points.midLeft.shiftFractionTowards(points.midRight, 0.65)
|
||||||
|
snippets.logo = new Snippet('logo', points.logo).scale(0.666)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the title
|
||||||
|
*/
|
||||||
|
points.title = points.logo.shift(0, 70)
|
||||||
|
macro('title', {
|
||||||
|
at: points.title,
|
||||||
|
nr: 7,
|
||||||
|
title: 'waistband',
|
||||||
|
align: 'center',
|
||||||
|
scale: 0.666,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the button hole
|
||||||
|
*/
|
||||||
|
snippets.buttonhole = new Snippet('buttonhole-start', points.buttonhole)
|
||||||
|
.attr('data-scale', absoluteOptions.waistbandWidth / 16)
|
||||||
|
.attr('data-rotate', 90)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the button
|
||||||
|
*/
|
||||||
|
snippets.button = new Snippet('button', points.button).attr(
|
||||||
|
'data-scale',
|
||||||
|
absoluteOptions.waistbandWidth / 16
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add notches to indicate the location of the seams
|
||||||
|
*/
|
||||||
|
macro('sprinkle', {
|
||||||
|
snippet: 'notch',
|
||||||
|
on: [
|
||||||
|
'leftSideTop',
|
||||||
|
'rightSideTop',
|
||||||
|
'leftFrontTop',
|
||||||
|
'cbTop',
|
||||||
|
'leftSideBottom',
|
||||||
|
'rightSideBottom',
|
||||||
|
'leftFrontBottom',
|
||||||
|
'cbBottom',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a grainline indicator
|
||||||
|
*/
|
||||||
|
points.grainlineTop = points.leftFrontTop.shiftFractionTowards(points.leftFrontLoopTop, 0.5)
|
||||||
|
points.grainlineBottom = new Point(points.grainlineTop.x, points.cbBottom.y)
|
||||||
|
macro('grainline', {
|
||||||
|
from: points.grainlineBottom,
|
||||||
|
to: points.grainlineTop,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions
|
||||||
|
*/
|
||||||
|
macro('hd', {
|
||||||
|
id: 'frontLeft',
|
||||||
|
from: points.leftFrontBottom,
|
||||||
|
to: points.leftSideBottom,
|
||||||
|
y: points.cbBottom.y + 15 + sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'backLeft',
|
||||||
|
from: points.leftSideBottom,
|
||||||
|
to: points.cbBottom,
|
||||||
|
y: points.cbBottom.y + 15 + sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'backRight',
|
||||||
|
from: points.cbBottom,
|
||||||
|
to: points.rightSideBottom,
|
||||||
|
y: points.cbBottom.y + 15 + sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'frontRight',
|
||||||
|
from: points.rightSideBottom,
|
||||||
|
to: points.rightFrontBottom,
|
||||||
|
y: points.cbBottom.y + 15 + sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'overlapRight',
|
||||||
|
from: points.rightFrontBottom,
|
||||||
|
to: points.rightEdgeBottom,
|
||||||
|
y: points.cbBottom.y + 15 + sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'leftHalf',
|
||||||
|
from: points.leftFrontBottom,
|
||||||
|
to: points.cbBottom,
|
||||||
|
y: points.cbBottom.y + 30 + sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'rightHalf',
|
||||||
|
from: points.cbBottom,
|
||||||
|
to: points.rightFrontBottom,
|
||||||
|
y: points.cbBottom.y + 30 + sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'fullLength',
|
||||||
|
from: points.leftFrontBottom,
|
||||||
|
to: points.rightEdgeBottom,
|
||||||
|
y: points.cbBottom.y + 45 + sa,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'buttonHeight',
|
||||||
|
from: points.rightEdgeBottom,
|
||||||
|
to: points.button,
|
||||||
|
x: points.rightEdgeBottom.x + 15 + sa,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'buttonHoleHeight',
|
||||||
|
from: points.leftFrontBottom,
|
||||||
|
to: points.buttonhole,
|
||||||
|
x: points.leftFrontBottom.x - sa - 15,
|
||||||
|
})
|
||||||
|
macro('vd', {
|
||||||
|
id: 'fullWidth',
|
||||||
|
from: points.leftFrontBottom,
|
||||||
|
to: points.leftFrontTop,
|
||||||
|
x: points.leftFrontBottom.x - sa - 30,
|
||||||
|
scale: 0.5,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'belLoopLeftFront',
|
||||||
|
from: points.leftFrontTop,
|
||||||
|
to: points.leftFrontLoopTop,
|
||||||
|
y: points.cbTop.y - 30 - sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'beltLoopLeftSide',
|
||||||
|
from: points.leftFrontLoopTop,
|
||||||
|
to: points.leftSideLoopTop,
|
||||||
|
y: points.cbTop.y - 30 - sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'beltLoopLeftBack',
|
||||||
|
from: points.leftSideLoopTop,
|
||||||
|
to: points.leftBackLoopTop,
|
||||||
|
y: points.cbTop.y - 30 - sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'beltLoopLeftCb',
|
||||||
|
from: points.leftBackLoopTop,
|
||||||
|
to: points.cbTop,
|
||||||
|
y: points.cbTop.y - 30 - sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'beltLoopRightCb',
|
||||||
|
from: points.cbTop,
|
||||||
|
to: points.rightBackLoopTop,
|
||||||
|
y: points.cbTop.y - 30 - sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'beltLoopRightBack',
|
||||||
|
from: points.rightBackLoopTop,
|
||||||
|
to: points.rightSideLoopTop,
|
||||||
|
y: points.cbTop.y - 30 - sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'beltLoopRightSide',
|
||||||
|
from: points.rightSideLoopTop,
|
||||||
|
to: points.rightFrontLoopTop,
|
||||||
|
y: points.cbTop.y - 30 - sa,
|
||||||
|
})
|
||||||
|
macro('hd', {
|
||||||
|
id: 'beltLoopRightFront',
|
||||||
|
from: points.rightFrontLoopTop,
|
||||||
|
to: points.rightFrontTop,
|
||||||
|
y: points.cbTop.y - 30 - sa,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
20
designs/naomiwu/tests/shared.test.mjs
Normal file
20
designs/naomiwu/tests/shared.test.mjs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// This file is auto-generated | Any changes you make will be overwritten.
|
||||||
|
import { Naomiwu, i18n } from '../src/index.mjs'
|
||||||
|
|
||||||
|
// Shared tests
|
||||||
|
import { testPatternConfig } from '../../../tests/designs/config.mjs'
|
||||||
|
import { testPatternI18n } from '../../../tests/designs/i18n.mjs'
|
||||||
|
import { testPatternDrafting } from '../../../tests/designs/drafting.mjs'
|
||||||
|
import { testPatternSampling } from '../../../tests/designs/sampling.mjs'
|
||||||
|
|
||||||
|
// Test config
|
||||||
|
testPatternConfig(Naomiwu)
|
||||||
|
|
||||||
|
// Test translation
|
||||||
|
testPatternI18n(Naomiwu, i18n)
|
||||||
|
|
||||||
|
// Test drafting - Change the second parameter to `true` to log errors
|
||||||
|
testPatternDrafting(Naomiwu, false)
|
||||||
|
|
||||||
|
// Test sampling - Change the second parameter to `true` to log errors
|
||||||
|
testPatternSampling(Naomiwu, false)
|
|
@ -9,31 +9,24 @@ provides the [Point.addText()](/reference/api/point/addtext) and
|
||||||
[Path.addText()](/reference/api/path/addtext) methods to let you add text to
|
[Path.addText()](/reference/api/path/addtext) methods to let you add text to
|
||||||
points and paths.
|
points and paths.
|
||||||
|
|
||||||
<Example caption="An example of adding text" tutorial>
|
In addition, [the `title` macro](/reference/macros/title) not only lets you add a
|
||||||
```design/src/part.mjs
|
title to your part, it also allows you to add notes.
|
||||||
function draftPart = ({
|
|
||||||
Point,
|
|
||||||
points,
|
|
||||||
Path,
|
|
||||||
paths,
|
|
||||||
part
|
|
||||||
}) {
|
|
||||||
|
|
||||||
points.demo = new Point(70,10)
|
## Wrapping lines
|
||||||
// highlight-start
|
|
||||||
.addText('Text on a point', 'center')
|
|
||||||
// highlight-end
|
|
||||||
|
|
||||||
paths.demo = new Path()
|
SVG does not provide any line-wrapping, so you will need to be mindful of that when you add longer text.
|
||||||
.move(new Point(0,0))
|
|
||||||
.line(new Point(100, 40))
|
|
||||||
.addClass('note dotted stroke-sm')
|
|
||||||
// highlight-start
|
|
||||||
.addText('Text on a path', 'center')
|
|
||||||
// highlight-end
|
|
||||||
|
|
||||||
|
To facilitate this, FreeSewing will enforce a line break when you use `\n` in your text.
|
||||||
|
|
||||||
|
## Translation
|
||||||
|
|
||||||
|
Text that is added to a pattern typically requires translation.
|
||||||
|
You should break up your text in such a way that it remains possible to translate it.
|
||||||
|
|
||||||
|
You can do that either via repeated calls to `addText()` or you can pass an array of strings, or even a nested array of strings, and FreeSewing will translate all individual pieces prior to contatenating them.
|
||||||
|
|
||||||
|
<Note compact noP>
|
||||||
|
|
||||||
|
Refer to [the `insertText` hook](/reference/hooks/inserttext#notes) for details.
|
||||||
|
</Note>
|
||||||
|
|
||||||
return part
|
|
||||||
}
|
|
||||||
```
|
|
||||||
</Example>
|
|
||||||
|
|
|
@ -35,16 +35,6 @@ Stack objects come with the following properties:
|
||||||
- `anchor` : A [Point](/reference/api/point) that is used as the anchor to align parts in the stack
|
- `anchor` : A [Point](/reference/api/point) that is used as the anchor to align parts in the stack
|
||||||
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
<Example caption="Example of the Stack constructor">
|
|
||||||
```js
|
|
||||||
import { Stack } from '@freesewing/core'
|
|
||||||
|
|
||||||
const myStack = new Stack('mystack')
|
|
||||||
```
|
|
||||||
</Example>
|
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
A Stack object exposes the following methods:
|
A Stack object exposes the following methods:
|
||||||
|
|
|
@ -47,6 +47,24 @@ Now you can use these macros in your part:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Removing macros and the role of the macro id
|
||||||
|
|
||||||
|
Many macros accept an `id` parameter as part of their configuration. This `id`
|
||||||
|
is used to generate the names for paths, points, or snippets that are added to
|
||||||
|
the part by the macro. This way, macro-added content is deterministic, and can
|
||||||
|
be removed again.
|
||||||
|
|
||||||
|
Each macro typically has an `rm`-prefixed counterpart that removes the (changed
|
||||||
|
done by) the macro. For example, you can add a bartack with the `bartack`
|
||||||
|
macro, and it can be removed with the `rmbartack` macro. For this removal to
|
||||||
|
work, and id must be set in the macro, and it must be passed when removing the
|
||||||
|
macro.
|
||||||
|
|
||||||
|
For macros that are typically used once per part (such as the `title` macro)
|
||||||
|
you can rely on the default id. For macros typically used multiple times (such
|
||||||
|
as the various dimension macros) you should set an id that is unique within the
|
||||||
|
part for each invocation.
|
||||||
|
|
||||||
## Macros we maintain
|
## Macros we maintain
|
||||||
|
|
||||||
Below is a list of macros from [the plugins we maintain](/reference/plugins).
|
Below is a list of macros from [the plugins we maintain](/reference/plugins).
|
||||||
|
|
|
@ -11,17 +11,26 @@ part of [core-plugins](/reference/plugins/core) (so it is available by default).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
macro('title', {
|
macro('title', {
|
||||||
String id = 'title',
|
String align = 'left',
|
||||||
String align,
|
Boolean append = false,
|
||||||
Boolean append,
|
|
||||||
Point at,
|
Point at,
|
||||||
Boolean cutlist
|
String brand = 'FreeSewing',
|
||||||
String nr,
|
Boolean cutlist = true,
|
||||||
String prefix,
|
Number dy = 8,
|
||||||
Number rotation,
|
|
||||||
Number scale,
|
|
||||||
String title,
|
|
||||||
Boolean force = false,
|
Boolean force = false,
|
||||||
|
String id = 'title',
|
||||||
|
Mixed notes = false,
|
||||||
|
String nr,
|
||||||
|
Number rotation = 0,
|
||||||
|
Number scale = 1,
|
||||||
|
String title = 'plugin-annotations:noName',
|
||||||
|
classes = {
|
||||||
|
String date: 'text-sm fill-current',
|
||||||
|
String name: 'fill-note',
|
||||||
|
String notes: 'text-md fill-current',
|
||||||
|
String nr: 'text-4xl fill-note font-bold',
|
||||||
|
String title: 'text-lg fill-current font-bold',
|
||||||
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -34,18 +43,28 @@ macro('title', {
|
||||||
// This is where name/version/etc. is supposed to be stored
|
// This is where name/version/etc. is supposed to be stored
|
||||||
store.set('data.version', 3)
|
store.set('data.version', 3)
|
||||||
store.set('data.name', 'Example')
|
store.set('data.name', 'Example')
|
||||||
store.set('data.for', 'Person')
|
store.set('data.for', 'Sorcha')
|
||||||
|
|
||||||
macro('title', {
|
macro('title', {
|
||||||
nr: 9,
|
nr: 8,
|
||||||
title: 'The title',
|
title: 'The Title',
|
||||||
at: new Point(0,0)
|
at: new Point(0,0),
|
||||||
|
brand: 'Bazooka Crew',
|
||||||
|
notes: [
|
||||||
|
"You can use any brand you want",
|
||||||
|
"\n",
|
||||||
|
"but if you plan to contribute your",
|
||||||
|
"\n",
|
||||||
|
"design, you should use the default",
|
||||||
|
"\n",
|
||||||
|
"(btw: These are the notes)"
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
// Prevent clipping
|
// Prevent clipping
|
||||||
paths.diag = new Path()
|
paths.diag = new Path()
|
||||||
.move(new Point(-20,-50))
|
.move(new Point(-20,-50))
|
||||||
.move(new Point(80,35))
|
.move(new Point(120,55))
|
||||||
|
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
@ -56,19 +75,30 @@ macro('title', {
|
||||||
|
|
||||||
| Property | Default | Type | Description |
|
| Property | Default | Type | Description |
|
||||||
| ----------:| :-----: | ------------------- | ----------- |
|
| ----------:| :-----: | ------------------- | ----------- |
|
||||||
| `align' | 'left' | String | Horizontal text alignment. Valid values: 'left', 'right', 'center' |
|
| `align` | `left` | String | Horizontal text alignment. One of `left`, `right`, or `center` |
|
||||||
| `append` | `false` | Boolean | Set this to `true` to append the `nr` to any text already set in Point `at`'s attributes, rather than overwrite it |
|
| `append` | `false` | Boolean | Set this to `true` to append the `nr`, rather than overwrite it |
|
||||||
| `at` | | [Point](/reference/api/point) | The point at which to insert the title |
|
| `at` | | [Point](/reference/api/point) | The point at which to insert the title |
|
||||||
| `cutlist` | `true` | Boolean | Whether to include cutting instructions |
|
| `brand` | `FreeSewing` | String | Brand name will prefix the design name |
|
||||||
| `id` | `title` | `string` | The ID of this macro instance |
|
| `classes.date` | `text-sm fill-current` | String | CSS classes for the date |
|
||||||
|
| `classes.name` | `fill-note` | String | CSS classes for the name |
|
||||||
|
| `classes.notes` | `text-md fill-current` | String | CSS classes for the notes |
|
||||||
|
| `classes.nr` | `text-4xl fill-note font-bold` | String | CSS classes for the nr |
|
||||||
|
| `classes.title` | `text-lg fill-current font-bold` | String | CSS classes for the title |
|
||||||
|
| `cutlist` | `true` | Boolean | Set this to `true` to prepend notes with the cutting instructions |
|
||||||
|
| `dy` | `8` | Number | SVG-equivalent of line height, controls the vertical spacing between text lines |
|
||||||
|
| `force` | `false` | `boolean` | Set this to `true` to display the macro output even when `complete` is `false` |
|
||||||
|
| `id` | `title` | `string` | The ID of this macro instance. See [Removing macros and the role of the macro id](/reference/macros#removing-macros-and-the-role-of-the-macro-id) |
|
||||||
|
| `notes` | | String | Any notes to go under the title |
|
||||||
| `nr` | | String | The number of the pattern part |
|
| `nr` | | String | The number of the pattern part |
|
||||||
| `title` | | String | The name of the pattern part. If title is not set or is an empty string, this won't be rendered, and the version will go beneath the nr.|
|
| `rotation` | `0` | Number | Rotation in degrees |
|
||||||
|
| `scale` | 1 | Number | An optional scaling factor to make the title bigger/smaller |
|
||||||
|
| `title` | `plugin-annotations:noName` | String | The name of the pattern part |
|
||||||
| `prefix` | | String | A prefix to add to the created points. This allow for more than 1 title per part, as long as you give them a different prefix.|
|
| `prefix` | | String | A prefix to add to the created points. This allow for more than 1 title per part, as long as you give them a different prefix.|
|
||||||
| `rotation` | 0 | Number | An optional rotation in degrees |
|
|
||||||
| `scale` | 1 | Number | An optional scaling factor |
|
|
||||||
| `force` | `false` | `boolean` | Set this to `true` to display the macro output even when `complete` is `false` |
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
This macro takes the `complete` setting into account and won't output anything when both complete and `force` are `false`.
|
- This macro takes the `complete` setting into account and won't output anything when both complete and `force` are `false`.
|
||||||
|
- This macro will check the value of `store.version` and `store.name` for the design version and name. These are auto-set by core.
|
||||||
|
- This macro will check the value of `store.for` for info of who this pattern was generated for. This is something to be done at run-time by your frontend.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
title: "100% full Sandy by lasermonkey12"
|
||||||
|
caption: "We love the dotty fabric"
|
||||||
|
date: 20240106
|
||||||
|
intro: "This Sandy circle skirt is a full circle."
|
||||||
|
designs: ["sandy"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
This Sandy circle skirt by maker lasermonkey12 is a 100% circle. We love the choice of fun fabric for this cute skirt!
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
title: "A charming small Lucy by moderndragon"
|
||||||
|
caption: "A small Lucy pocket"
|
||||||
|
date: 20240102
|
||||||
|
intro: "This small Lucy was moderndragon's very first FreeSewing make."
|
||||||
|
designs: ["lucy"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
This small Lucy pocket was moderndragon's very first FreeSewing make. We think the size, pattern placement, binding, and finishing are all very lovely!
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
title: "A delightfully drapey Teagan by lasermonkey12"
|
||||||
|
caption: "This Teagan t-shirt has lovely drape."
|
||||||
|
date: 20240106
|
||||||
|
intro: "Maker lasermonkey12 shared this very wearable Teagan tee."
|
||||||
|
designs: ["teagan"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
Maker lasermonkey12 shared this very wearable Teagan tee. The dotty fabric is the festive cousin of the one she used for her Sandy circle skirt, also viewable in a separate showcase post. This was shared on our [Discord](https://discord.freesewing.org/) and has been reposted here with permission.
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
title: "A Simone + Sandy mashup with a handkerchief hem by RockerKitten"
|
||||||
|
caption: "The front view of this Simone + Sandy dress"
|
||||||
|
date: 20240106
|
||||||
|
intro: "RockerKitten combined Simone and Sandy to make this gorgeous dress."
|
||||||
|
designs: ["simone", "sandy"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
RockerKitten combined Simone and Sandy to make this gorgeous dress. We enjoyed following their progress on [Discord](https://discord.freesewing.org/), from inspo pic to final result! RK has really dialed in their FreeSewing measurements and options, with a fantastic result.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This was made by RockerKitten, [@rockerkitten on Instagram](https://www.instagram.com/rockerkitten/), and has been shared here with permission.
|
||||||
|
|
11
markdown/org/showcase/a-squid-friend-for-octopus/en.md
Normal file
11
markdown/org/showcase/a-squid-friend-for-octopus/en.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
title: "A squid friend for octopus"
|
||||||
|
caption: "This sweet blue creature was made as a buddy for the XL Octoplushy."
|
||||||
|
date: 20240106
|
||||||
|
intro: "That Octoplushy is a squid (variant)!"
|
||||||
|
designs: ["octoplushy"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
That Octoplushy is a squid (variant)! lasermonkey12 made this blue squid as a friend for her previous octopus version.
|
||||||
|
|
24
markdown/org/showcase/a-very-modified-yuri/en.md
Normal file
24
markdown/org/showcase/a-very-modified-yuri/en.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
title: "A very modified Yuri"
|
||||||
|
caption: "Yuri robe, now with pockets"
|
||||||
|
date: 20240106
|
||||||
|
intro: "RockerKitten modified Yuri to make this cozy and cute robe."
|
||||||
|
designs: ["yuri"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
RockerKitten modified Yuri to make this cozy and cute robe. They changed the neck line, lengthened the front hood, and made the whole thing floor length. They shared:
|
||||||
|
|
||||||
|
> it was exactly the type of hood I wanted, and the perfect base. I hate drafting sleeve caps and armscyes so that's what I use the most of 😄
|
||||||
|
I was really really really happy that the hood fit lol. I NEVER find hoods that fit
|
||||||
|
|
||||||
|
Yay! Love the way they took Yuri's base design and made it their own.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This was made by RockerKitten, [@rockerkitten on Instagram](https://www.instagram.com/rockerkitten/), and has been shared here with permission.
|
||||||
|
|
13
markdown/org/showcase/a-wearable-sandy-muslin/en.md
Normal file
13
markdown/org/showcase/a-wearable-sandy-muslin/en.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: "A wearable Sandy muslin"
|
||||||
|
caption: "Sandy 'muslin' but also wearable"
|
||||||
|
date: 20240106
|
||||||
|
intro: "Sometimes simple is perfect! RockerKitten made this Sandy skirt as a wearable muslin."
|
||||||
|
designs: ["sandy"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
Sometimes simple is perfect! RockerKitten made this Sandy skirt as a wearable muslin. We think this looks wonderfully wearable -- the perfect piece for lots of outfits.
|
||||||
|
|
||||||
|
This was made by RockerKitten, [@rockerkitten on Instagram](https://www.instagram.com/rockerkitten/), and has been shared here with permission.
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: "Bruce with a flat front and lengthened legs"
|
||||||
|
caption: "A flat-front Bruce"
|
||||||
|
date: 20240102
|
||||||
|
intro: "This flat-front Bruce is a bit wider and with longer legs. They're the most comfy ever while still somewhat flattening the anatomy."
|
||||||
|
designs: ["bruce"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
These flat-front Bruces by Halbmoki, are a bit wider and with longer legs than their last version. They said these Bruce boxer briefs are the most comfy ever while still somewhat flattening the anatomy. Looks great!
|
||||||
|
|
||||||
|

|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: "Florent lined with lasermonkey12's favorite Dr Seuss book"
|
||||||
|
caption: "lasermonkey12 looks great in this Florent flat cap"
|
||||||
|
date: 20240106
|
||||||
|
intro: "Don't miss the sweet lining fabric on this Florent flat cap."
|
||||||
|
designs: ["florent"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
Don't miss the sweet lining fabric on this Florent flat cap. Maker lasermonkey12 lined it with her favorite Dr Seuss book:
|
||||||
|
|
||||||
|

|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
title: "Hand-stitched Teagans by Vili, with explanation of the stitches"
|
||||||
|
caption: "A hand-stitched Teagan"
|
||||||
|
date: 20240106
|
||||||
|
intro: "The FreeSewing community enjoyed following Vili's explorations of different hand stitch options on the Teagan t-shirt!"
|
||||||
|
designs: ["teagan"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
The FreeSewing community enjoyed following Vili's explorations of different hand stitch options on the Teagan t-shirt! Hand-stitching stretch fabrics is rather unusual and presented challenges, but we think the result looks great.
|
||||||
|
|
||||||
|
Read on for more descriptions and photos of Vili's process.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The maker shared:
|
||||||
|
|
||||||
|
> My first idea was to use a blanket stitch, honestly can't remember where I got this idea. This didn't work very well, as you either had to leave the stitches loose, allowing the seam to gape, or pull it tight making the seam bulky.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> The second idea was to do a fine/short stitch length herringbone stitch. This worked well, and allows the fabric to stretch as much as it would without the stitch! It does use a bunch of thread done this way, and is laborious, but it works.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> My last experiment, and the stitch I'm going to be using for this from now on, is the humble backstitch! It's more efficient than the herringbone, and works just as well for parts that don't need a lot of stretch. Aside from the blanket stitch, the edges were left unfinished, which has worked out fine.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> For hemming, I tried both a herringbone with every other stitch being super long (there are other ways of course) and a backstitch. The herringbone works, but I preferred the look of the backstitch. It should be noted that a hand-sewn backstitch has a lot more stretch than a machine-sewn straight stitch, so it's worth testing and seeing if it could work for you, even when some strech is needed!
|
||||||
|
|
||||||
|

|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: "Lumira leggings with cycling chamois"
|
||||||
|
caption: "This is Lumira's designer, Wouter, testing out his new leggings"
|
||||||
|
date: 20240104
|
||||||
|
intro: "The Lumira leggings are designed with many options, including a waistband, optional gusset, and bulge option."
|
||||||
|
designs: ["lumira"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
The Lumira leggings are designed with many options, including a waistband, optional gusset, and bulge option. This particular version is with the cycling chamois, but the same design works for yoga leggings and anything in between too. We're all excited to fill our closets with Lumira variations!
|
||||||
|
|
||||||
|

|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
title: "RockerKitten's Simone muslin with a few modifications"
|
||||||
|
caption: "RockerKitten sewed this muslin of the Simone shirt"
|
||||||
|
date: 20240106
|
||||||
|
intro: "RockerKitten sewed this muslin of the Simone shirt with a few mods."
|
||||||
|
designs: ["simone"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
RockerKitten sewed this muslin of the Simone shirt with a few mods.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This was made by RockerKitten, [@rockerkitten on Instagram](https://www.instagram.com/rockerkitten/), and has been shared here with permission.
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
title: "Simon by lasermonkey12, feat. hand-sewn buttonholes"
|
||||||
|
caption: "Don't miss the details on this great-looking Simon"
|
||||||
|
date: 20240106
|
||||||
|
intro: "This Simon shirt features hand-sewn buttonholes and a home-patterned tower placket."
|
||||||
|
designs: ["simon"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
This Simon shirt by maker lasermonkey12 features hand-sewn buttonholes and a home-patterned tower placket.
|
||||||
|
|
||||||
|
She shared that this version has hand-sewn buttonholes and a home-patterned tower placket. The detail photos below include the accent fabric for placket, inside undercollar and inside cuffs because it's fun!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
These photos were shared by lasermonkey12 on [Discord](https://discord.freesewing.org/), and have been reposted here with permission.
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
title: "Sleeveless Simon by lasermonkey12"
|
||||||
|
caption: "A sleeveless Simon shirt"
|
||||||
|
date: 20240106
|
||||||
|
intro: "Maker lasermonkey12 has made lots of great Simon shirts, including this sleeveless one."
|
||||||
|
designs: ["simon"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
Maker lasermonkey12 has made lots of great Simon shirts, including this sleeveless one. We love the fresh look, well-suited for hot weather! This was shared on [Discord](https://discord.freesewing.org/) and is reposted here with permission.
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: "Surprise-giant Hi by lasermonkey12"
|
||||||
|
caption: "A hilariously large Hi"
|
||||||
|
date: 20240106
|
||||||
|
intro: "Bet you can't guess how small this Hi shark packed down."
|
||||||
|
designs: ["hi"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
Bet you can't guess how small this Hi shark packed down. Maker lasermonkey12 shared:
|
||||||
|
|
||||||
|
> i asked a friend if i could send him an empty plushie with a zipper installed and have him stuff it. he did not expect me to make it this large (and i intentionally packed it as small as possible)
|
||||||
|
|
||||||
|
Best. Delivery. Ever.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
15
markdown/org/showcase/the-bella-block-by-rockerkitten/en.md
Normal file
15
markdown/org/showcase/the-bella-block-by-rockerkitten/en.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
title: "The Bella block by RockerKitten"
|
||||||
|
caption: "A muslin of Bella"
|
||||||
|
date: 20240106
|
||||||
|
intro: "The Bella block is what brought RockerKitten to FreeSewing -- and we couldn't be more grateful that she found us!"
|
||||||
|
designs: ["bella"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
The Bella block is what brought RockerKitten to FreeSewing -- and we couldn't be more grateful that she found us! She has dialed in her preferences and measurements to find her ideal fit. This is one of her muslins.
|
||||||
|
|
||||||
|
RockerKitten graciously shares tips, encouragement, and advice with folks on [Discord](https://discord.freesewing.org/). Come join the discussion over there if you're interested in trying FreeSewing's blocks!
|
||||||
|
|
||||||
|
This was made by RockerKitten, [@rockerkitten on Instagram](https://www.instagram.com/rockerkitten/), and has been shared here with permission.
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: "Two short-sleeved Simons by lasermonkey12"
|
||||||
|
caption: "A cheerful yellow Simon shirt"
|
||||||
|
date: 20240106
|
||||||
|
intro: "lasermonkey12 shortened the sleeves on these two Simon shirts."
|
||||||
|
designs: ["simon"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
lasermonkey12 shortened the sleeves on these two Simon shirts. I've cheated by putting them together in a single showcase post. Love this variation! Great stitch details and fabric choices.
|
||||||
|
|
||||||
|

|
||||||
|
|
21
markdown/org/showcase/xl-octoplushy-by-lasermonkey12/en.md
Normal file
21
markdown/org/showcase/xl-octoplushy-by-lasermonkey12/en.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: "XL Octoplushy by lasermonkey12"
|
||||||
|
caption: "Octoplushy, stuffing in progress"
|
||||||
|
date: 20240106
|
||||||
|
intro: "Not sure what to do with your scraps? Let us introduce the best idea ever: an XL Octoplushy."
|
||||||
|
designs: ["octoplushy"]
|
||||||
|
maker: Natalia
|
||||||
|
---
|
||||||
|
|
||||||
|
Not sure what to do with your scraps? Let us introduce the best idea ever: an XL Octoplushy. This was made by lasermonkey12 who shared on [Discord](https://discord.freesewing.org/) and granted us permission to repost here. She notes that this Octoplushy is stuffed with scraps and is not full yet, thus the zipper.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
},
|
},
|
||||||
"peerDependencies": {},
|
"peerDependencies": {},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "1.6.3",
|
"axios": "1.6.5",
|
||||||
"chalk": "5.3.0",
|
"chalk": "5.3.0",
|
||||||
"execa": "8.0.1",
|
"execa": "8.0.1",
|
||||||
"mustache": "4.2.0",
|
"mustache": "4.2.0",
|
||||||
|
|
|
@ -71,7 +71,8 @@ export const getId = ({
|
||||||
export const translateStrings = (t, list) => {
|
export const translateStrings = (t, list) => {
|
||||||
let translated = ''
|
let translated = ''
|
||||||
for (const string of list) {
|
for (const string of list) {
|
||||||
if (string) translated += t(string.toString()).replace(/"/g, '"') + ' '
|
if (Array.isArray(string)) translated += translateStrings(t, string)
|
||||||
|
else if (string) translated += t(string.toString()).replace(/"/g, '"') + ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
return translated
|
return translated
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
const capitalize = (string) =>
|
||||||
|
typeof string === 'string' ? string.charAt(0).toUpperCase() + string.slice(1) : ''
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Defaults for the title macro
|
* Defaults for the title macro
|
||||||
*/
|
*/
|
||||||
|
@ -12,10 +15,11 @@ const macroDefaults = {
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
title: 'plugin-annotations:noName',
|
title: 'plugin-annotations:noName',
|
||||||
|
notes: false,
|
||||||
|
brand: 'FreeSewing',
|
||||||
classes: {
|
classes: {
|
||||||
cutlist: 'text-md fill-current',
|
notes: 'text-md fill-current',
|
||||||
date: 'text-sm fill-current',
|
date: 'text-sm fill-current',
|
||||||
for: 'fill-current font-bold',
|
|
||||||
name: 'fill-note',
|
name: 'fill-note',
|
||||||
nr: 'text-4xl fill-note font-bold',
|
nr: 'text-4xl fill-note font-bold',
|
||||||
title: 'text-lg fill-current font-bold',
|
title: 'text-lg fill-current font-bold',
|
||||||
|
@ -74,9 +78,8 @@ const title = function (config, { Point, points, scale, locale, store, part, log
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the list of IDs
|
* Get the list of IDs
|
||||||
* Initialize the verticle cadence
|
|
||||||
*/
|
*/
|
||||||
const ids = store.generateMacroIds(['cutlist', 'date', 'for', 'name', 'nr', 'title'], mc.id)
|
const ids = store.generateMacroIds(['nr', 'date', 'title', 'name', 'notes'], mc.id)
|
||||||
|
|
||||||
let shift = mc.dy
|
let shift = mc.dy
|
||||||
|
|
||||||
|
@ -93,6 +96,24 @@ const title = function (config, { Point, points, scale, locale, store, part, log
|
||||||
store.set(['partNumbers', part.name], mc.nr)
|
store.set(['partNumbers', part.name], mc.nr)
|
||||||
} else delete ids.nr
|
} else delete ids.nr
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Title: date
|
||||||
|
*/
|
||||||
|
points[ids.date] = mc.at
|
||||||
|
.shift(-90, shift / 2)
|
||||||
|
.addText(
|
||||||
|
new Date().toLocaleString(locale || 'en', {
|
||||||
|
weekday: 'long',
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
}),
|
||||||
|
`${mc.classes.date} ${mc.align}`
|
||||||
|
)
|
||||||
|
.attr('data-text-transform', transform)
|
||||||
|
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
||||||
|
shift += mc.dy
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Title: title
|
* Title: title
|
||||||
*/
|
*/
|
||||||
|
@ -100,18 +121,39 @@ const title = function (config, { Point, points, scale, locale, store, part, log
|
||||||
points[ids.title] = mc.at
|
points[ids.title] = mc.at
|
||||||
.clone()
|
.clone()
|
||||||
.shift(-90, shift)
|
.shift(-90, shift)
|
||||||
.attr('data-text', mc.title, mc.append ? false : true)
|
|
||||||
.attr('data-text-class', `${mc.classes.title} ${mc.align}`)
|
|
||||||
.attr('data-text-transform', transform)
|
.attr('data-text-transform', transform)
|
||||||
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
||||||
|
if (mc.append) points[ids.title].addText(mc.title, `${mc.classes.title} ${mc.align}`)
|
||||||
|
else points[ids.title].setText(mc.title, `${mc.classes.title} ${mc.align}`)
|
||||||
shift += mc.dy
|
shift += mc.dy
|
||||||
store.set(['partTitles', part.name], mc.title)
|
store.set(['partTitles', part.name], mc.title)
|
||||||
} else delete ids.title
|
} else delete ids.title
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Title: cutlist
|
* Title: name
|
||||||
*/
|
*/
|
||||||
|
points[ids.name] = mc.at
|
||||||
|
.clone()
|
||||||
|
.shift(-90, shift)
|
||||||
|
.addText(
|
||||||
|
`${mc.brand} ${capitalize(
|
||||||
|
(store.data?.name || 'plugin-annotations:noName').replace('@freesewing/', '')
|
||||||
|
)} v${store.data?.version || 'plugin-annotations:noVersion'} (`,
|
||||||
|
|
||||||
|
`${mc.classes.name} ${mc.align}`
|
||||||
|
)
|
||||||
|
.addText(store.data?.for ? store.data.for : 'ephemeral')
|
||||||
|
.addText(')')
|
||||||
|
.attr('data-text-transform', transform)
|
||||||
|
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
||||||
|
shift += mc.dy
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Title: notes
|
||||||
|
*/
|
||||||
|
const notes = []
|
||||||
if (mc.cutlist) {
|
if (mc.cutlist) {
|
||||||
|
points[ids.notes] = mc.at.clone().shift(-90, shift)
|
||||||
/*
|
/*
|
||||||
* Get cutlist instructions from the store, only proceed if the list is available
|
* Get cutlist instructions from the store, only proceed if the list is available
|
||||||
*/
|
*/
|
||||||
|
@ -121,94 +163,39 @@ const title = function (config, { Point, points, scale, locale, store, part, log
|
||||||
* Iterate over materials
|
* Iterate over materials
|
||||||
*/
|
*/
|
||||||
for (const [material, instructions] of Object.entries(partCutlist.materials)) {
|
for (const [material, instructions] of Object.entries(partCutlist.materials)) {
|
||||||
instructions.forEach(({ cut, identical, onBias, onFold }, c) => {
|
instructions.forEach(({ cut, identical, onBias, onFold }) => {
|
||||||
/*
|
/*
|
||||||
* Create point
|
* Concat line
|
||||||
*/
|
|
||||||
const id = `${ids.cutlist}_${material}_${c}`
|
|
||||||
ids[`cutlist_${material}_${c}`] = id
|
|
||||||
points[id] = mc.at
|
|
||||||
.clone()
|
|
||||||
.shift(-90, shift)
|
|
||||||
.attr('data-text', 'plugin-annotations:cut')
|
|
||||||
.attr('data-text-class', `${mc.classes.cutlist} ${mc.align}`)
|
|
||||||
.attr('data-text-transform', transform)
|
|
||||||
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
|
||||||
.addText(cut)
|
|
||||||
shift += mc.dy
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add instructions if parts are mirrored
|
|
||||||
*/
|
|
||||||
if (!identical && cut > 1) points[id].addText('plugin-annotations:mirrored')
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add instructions if parts are cut on fold
|
|
||||||
*/
|
*/
|
||||||
|
notes.push('plugin-annotations:cut')
|
||||||
|
notes.push(cut)
|
||||||
|
if (!identical && cut > 1) notes.push('plugin-annotations:mirrored')
|
||||||
if (onFold)
|
if (onFold)
|
||||||
points[id].addText(
|
notes.push(onBias ? 'plugin-annotations:onFoldAndBias' : 'plugin-annotations:onFold')
|
||||||
onBias ? 'plugin-annotations:onFoldAndBias' : 'plugin-annotations:onFold'
|
else if (onBias) notes.push('plugin-annotations:onBias')
|
||||||
)
|
notes.push('plugin-annotations:from', 'plugin-annotations:' + material)
|
||||||
/*
|
/*
|
||||||
* Add instructions if parts on on bias
|
* Force a line break between materials
|
||||||
*/ else if (onBias) points[id].addText('plugin-annotations:onBias')
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add 'from' (material) text
|
|
||||||
*/
|
*/
|
||||||
points[id].addText('plugin-annotations:from').addText('plugin-annotations:' + material)
|
notes.push('\n')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else delete ids.cutlist
|
}
|
||||||
|
if (mc.notes) {
|
||||||
/*
|
if (Array.isArray(mc.notes)) notes.push(...mc.notes)
|
||||||
* Title: Design name
|
else notes.push(mc.notes)
|
||||||
*/
|
}
|
||||||
points[ids.name] = mc.at
|
if (notes.length > 0) {
|
||||||
.clone()
|
/*
|
||||||
.shift(-90, shift)
|
* Add all text on a single point
|
||||||
.attr(
|
*/
|
||||||
'data-text',
|
points[ids.notes]
|
||||||
`${(store.data?.name || 'plugin-annotations:noName').replace('@freesewing/', '')} v${
|
.addText(notes, `${mc.classes.notes} ${mc.align}`)
|
||||||
store.data?.version || 'plugin-annotations:noVersion'
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
.attr('data-text-class', `${mc.classes.name} ${mc.align}`)
|
|
||||||
.attr('data-text-transform', transform)
|
|
||||||
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
|
||||||
shift += mc.dy
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Title: For (measurements set)
|
|
||||||
*/
|
|
||||||
if (store.data.for) {
|
|
||||||
points[ids.for] = mc.at
|
|
||||||
.shift(-90, shift)
|
|
||||||
.attr('data-text', `(${store.data.for})`)
|
|
||||||
.attr('data-text-class', `${mc.classes.for} ${mc.align}`)
|
|
||||||
.attr('data-text-transform', transform)
|
.attr('data-text-transform', transform)
|
||||||
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
||||||
shift += mc.dy
|
.attr('data-text-lineheight', mc.dy)
|
||||||
} else delete ids.for
|
} else delete ids.cutlist
|
||||||
|
|
||||||
/*
|
|
||||||
* Title: Date
|
|
||||||
*/
|
|
||||||
points[ids.date] = mc.at
|
|
||||||
.shift(-90, shift)
|
|
||||||
.attr(
|
|
||||||
'data-text',
|
|
||||||
new Date().toLocaleString(locale || 'en', {
|
|
||||||
weekday: 'long',
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'short',
|
|
||||||
day: 'numeric',
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.attr('data-text-class', `${mc.classes.date} ${mc.align}`)
|
|
||||||
.attr('data-text-transform', transform)
|
|
||||||
.attr('data-render-always', 1) // Render even when outside the part bounding box
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store all IDs in the store so we can remove this macro with rmtitle
|
* Store all IDs in the store so we can remove this macro with rmtitle
|
||||||
|
|
|
@ -39,12 +39,12 @@ describe('Title Plugin Tests', () => {
|
||||||
expect(p.attributes.get('data-text')).to.equal('unitTest')
|
expect(p.attributes.get('data-text')).to.equal('unitTest')
|
||||||
expect(p.attributes.get('data-text-class')).to.equal('text-lg fill-current font-bold left')
|
expect(p.attributes.get('data-text-class')).to.equal('text-lg fill-current font-bold left')
|
||||||
expect(p.attributes.get('data-text-x')).to.equal('-12')
|
expect(p.attributes.get('data-text-x')).to.equal('-12')
|
||||||
expect(p.attributes.get('data-text-y')).to.equal('-26')
|
expect(p.attributes.get('data-text-y')).to.equal('-18')
|
||||||
p = pattern.parts[0].test.points.__macro_title_title_name
|
p = pattern.parts[0].test.points.__macro_title_title_name
|
||||||
expect(p.attributes.get('data-text')).to.equal('testPattern v99')
|
expect(p.attributes.get('data-text')).to.equal('FreeSewing TestPattern v99 ( ephemeral )')
|
||||||
expect(p.attributes.get('data-text-class')).to.equal('fill-note left')
|
expect(p.attributes.get('data-text-class')).to.equal('fill-note left')
|
||||||
expect(p.attributes.get('data-text-x')).to.equal('-12')
|
expect(p.attributes.get('data-text-x')).to.equal('-12')
|
||||||
expect(p.attributes.get('data-text-y')).to.equal('-18')
|
expect(p.attributes.get('data-text-y')).to.equal('-10')
|
||||||
p = pattern.parts[0].test.points.__macro_title_title_date
|
p = pattern.parts[0].test.points.__macro_title_title_date
|
||||||
expect(p.attributes.get('data-text')).to.include(', 202')
|
expect(p.attributes.get('data-text')).to.include(', 202')
|
||||||
})
|
})
|
||||||
|
@ -117,12 +117,12 @@ describe('Title Plugin Tests', () => {
|
||||||
expect(p.attributes.get('data-text')).to.equal('unitTest')
|
expect(p.attributes.get('data-text')).to.equal('unitTest')
|
||||||
expect(p.attributes.get('data-text-class')).to.equal('text-lg fill-current font-bold left')
|
expect(p.attributes.get('data-text-class')).to.equal('text-lg fill-current font-bold left')
|
||||||
expect(p.attributes.get('data-text-x')).to.equal('-12')
|
expect(p.attributes.get('data-text-x')).to.equal('-12')
|
||||||
expect(p.attributes.get('data-text-y')).to.equal('-26')
|
expect(p.attributes.get('data-text-y')).to.equal('-18')
|
||||||
p = pattern.parts[0].test.points.__macro_title_foo_name
|
p = pattern.parts[0].test.points.__macro_title_foo_name
|
||||||
expect(p.attributes.get('data-text')).to.equal('testPattern v99')
|
expect(p.attributes.get('data-text')).to.equal('FreeSewing TestPattern v99 ( ephemeral )')
|
||||||
expect(p.attributes.get('data-text-class')).to.equal('fill-note left')
|
expect(p.attributes.get('data-text-class')).to.equal('fill-note left')
|
||||||
expect(p.attributes.get('data-text-x')).to.equal('-12')
|
expect(p.attributes.get('data-text-x')).to.equal('-12')
|
||||||
expect(p.attributes.get('data-text-y')).to.equal('-18')
|
expect(p.attributes.get('data-text-y')).to.equal('-10')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should run the title macro with custom alignment', () => {
|
it('Should run the title macro with custom alignment', () => {
|
||||||
|
@ -209,4 +209,63 @@ describe('Title Plugin Tests', () => {
|
||||||
)
|
)
|
||||||
expect(p.__macro_title_title_name.attributes.get('data-text-class')).to.equal('fill-note left')
|
expect(p.__macro_title_title_name.attributes.get('data-text-class')).to.equal('fill-note left')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should run the title macro with notes', () => {
|
||||||
|
const notes = 'These are the notes\nHere are some more notes'
|
||||||
|
const part = {
|
||||||
|
name: 'test',
|
||||||
|
draft: ({ points, Point, macro, part }) => {
|
||||||
|
points.anchor = new Point(-12, -34)
|
||||||
|
macro('title', {
|
||||||
|
at: points.anchor,
|
||||||
|
nr: 3,
|
||||||
|
title: 'unitTest',
|
||||||
|
notes,
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
},
|
||||||
|
plugins: [annotationsPlugin],
|
||||||
|
}
|
||||||
|
// Note that we're not loading core plugins but the local plugin
|
||||||
|
const Pattern = new Design({
|
||||||
|
data: { name: 'testPattern', version: 99 },
|
||||||
|
parts: [part],
|
||||||
|
noCorePlugins: true,
|
||||||
|
})
|
||||||
|
const pattern = new Pattern()
|
||||||
|
pattern.draft().render()
|
||||||
|
let p = pattern.parts[0].test.points.__macro_title_title_notes
|
||||||
|
expect(p.attributes.get('data-text')).to.equal(notes)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should run the title macro with a custom brand', () => {
|
||||||
|
const brand = 'Bazooka Patterns'
|
||||||
|
const part = {
|
||||||
|
name: 'test',
|
||||||
|
draft: ({ points, Point, macro, part }) => {
|
||||||
|
points.anchor = new Point(-12, -34)
|
||||||
|
macro('title', {
|
||||||
|
at: points.anchor,
|
||||||
|
nr: 3,
|
||||||
|
title: 'unitTest',
|
||||||
|
brand,
|
||||||
|
id: 'foo',
|
||||||
|
})
|
||||||
|
|
||||||
|
return part
|
||||||
|
},
|
||||||
|
plugins: [annotationsPlugin],
|
||||||
|
}
|
||||||
|
// Note that we're not loading core plugins but the local plugin
|
||||||
|
const Pattern = new Design({
|
||||||
|
data: { name: 'testPattern', version: 99 },
|
||||||
|
parts: [part],
|
||||||
|
noCorePlugins: true,
|
||||||
|
})
|
||||||
|
const pattern = new Pattern()
|
||||||
|
pattern.draft().render()
|
||||||
|
let p = pattern.parts[0].test.points.__macro_title_foo_name
|
||||||
|
expect(p.attributes.get('data-text')).to.equal(`${brand} TestPattern v99 ( ephemeral )`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,25 +1,33 @@
|
||||||
import { name, version } from '../data.mjs'
|
import { name, version } from '../data.mjs'
|
||||||
|
|
||||||
|
const translate = (locale, text, t, pattern) => {
|
||||||
|
/*
|
||||||
|
* Call oneself recursively if text is an array
|
||||||
|
*/
|
||||||
|
if (Array.isArray(text))
|
||||||
|
return text.map((string) => translate(locale, string, t, pattern)).join(' ')
|
||||||
|
|
||||||
|
if (t instanceof Function) return t(text, locale)
|
||||||
|
else if (typeof t[locale] === 'object') return t[locale][text] || text
|
||||||
|
else {
|
||||||
|
const msg =
|
||||||
|
"No translation method or object was passed to the i18n plugin. This plugin won't do anything without that"
|
||||||
|
if (pattern?.store?.log?.warn) {
|
||||||
|
if (!pattern.store.get(['plugins', 'plugin-i18n', 'missingMethodWarning'])) {
|
||||||
|
pattern.store.set(['plugins', 'plugin-i18n', 'missingMethodWarning'], true)
|
||||||
|
pattern.store.log.warn(msg)
|
||||||
|
}
|
||||||
|
} else console.log(msg)
|
||||||
|
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const plugin = {
|
export const plugin = {
|
||||||
name,
|
name,
|
||||||
version,
|
version,
|
||||||
hooks: {
|
hooks: {
|
||||||
insertText: (locale, text, t, pattern) => {
|
insertText: (locale, text, t, pattern) => translate(locale, text, t, pattern),
|
||||||
if (t instanceof Function) return t(text, locale)
|
|
||||||
else if (typeof t[locale] === 'object') return t[locale][text] || text
|
|
||||||
else {
|
|
||||||
const msg =
|
|
||||||
"No translation method or object was passed to the i18n plugin. This plugin won't do anything without that"
|
|
||||||
if (pattern?.store?.log?.warn) {
|
|
||||||
if (!pattern.store.get(['plugins', 'plugin-i18n', 'missingMethodWarning'])) {
|
|
||||||
pattern.store.set(['plugins', 'plugin-i18n', 'missingMethodWarning'], true)
|
|
||||||
pattern.store.log.warn(msg)
|
|
||||||
}
|
|
||||||
} else console.log(msg)
|
|
||||||
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,9 @@
|
||||||
"vbuild": "VERBOSE=1 node build.mjs",
|
"vbuild": "VERBOSE=1 node build.mjs",
|
||||||
"wbuild": "node build.mjs"
|
"wbuild": "node build.mjs"
|
||||||
},
|
},
|
||||||
|
"peerDependencies": {},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sesv2": "3.484.0",
|
"@aws-sdk/client-sesv2": "3.485.0",
|
||||||
"@prisma/client": "5.7.1",
|
"@prisma/client": "5.7.1",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
|
@ -54,9 +55,6 @@
|
||||||
"nodemon": "3.0.2",
|
"nodemon": "3.0.2",
|
||||||
"prisma": "5.7.1"
|
"prisma": "5.7.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
|
||||||
"sharp": "^0.33.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18",
|
"node": ">=18",
|
||||||
"npm": ">=9"
|
"npm": ">=9"
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-copy-to-clipboard": "5.1.0",
|
"react-copy-to-clipboard": "5.1.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-hotkeys-hook": "4.4.1",
|
"react-hotkeys-hook": "4.4.3",
|
||||||
"react-instantsearch-dom": "6.40.4",
|
"react-instantsearch-dom": "6.40.4",
|
||||||
"react-instantsearch-hooks-web": "6.47.3",
|
"react-instantsearch-hooks-web": "6.47.3",
|
||||||
"react-swipeable": "7.0.1",
|
"react-swipeable": "7.0.1",
|
||||||
|
@ -61,10 +61,10 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "10.4.16",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"postcss": "8.4.32",
|
"postcss": "8.4.33",
|
||||||
"remark-extract-frontmatter": "3.2.0",
|
"remark-extract-frontmatter": "3.2.0",
|
||||||
"remark-mdx-frontmatter": "4.0.0",
|
"remark-mdx-frontmatter": "4.0.0",
|
||||||
"tailwindcss": "3.4.0",
|
"tailwindcss": "3.4.1",
|
||||||
"yaml-loader": "0.8.0"
|
"yaml-loader": "0.8.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -36,16 +36,16 @@
|
||||||
"d3-drag": "3.0.0",
|
"d3-drag": "3.0.0",
|
||||||
"d3-selection": "3.0.0",
|
"d3-selection": "3.0.0",
|
||||||
"daisyui": "4.5.0",
|
"daisyui": "4.5.0",
|
||||||
"i18next": "23.7.13",
|
"i18next": "23.7.15",
|
||||||
"lodash.get": "4.4.2",
|
"lodash.get": "4.4.2",
|
||||||
"lodash.orderby": "4.6.0",
|
"lodash.orderby": "4.6.0",
|
||||||
"lodash.set": "4.3.2",
|
"lodash.set": "4.3.2",
|
||||||
"next": "14.0.4",
|
"next": "14.0.4",
|
||||||
"next-i18next": "15.1.2",
|
"next-i18next": "15.2.0",
|
||||||
"ora": "8.0.1",
|
"ora": "8.0.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-copy-to-clipboard": "5.1.0",
|
"react-copy-to-clipboard": "5.1.0",
|
||||||
"react-hotkeys-hook": "4.4.1",
|
"react-hotkeys-hook": "4.4.3",
|
||||||
"react-i18next": "13.5.0",
|
"react-i18next": "13.5.0",
|
||||||
"react-instantsearch-dom": "6.40.4",
|
"react-instantsearch-dom": "6.40.4",
|
||||||
"react-swipeable": "7.0.1",
|
"react-swipeable": "7.0.1",
|
||||||
|
@ -62,10 +62,10 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "10.4.16",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"postcss": "8.4.32",
|
"postcss": "8.4.33",
|
||||||
"remark-extract-frontmatter": "3.2.0",
|
"remark-extract-frontmatter": "3.2.0",
|
||||||
"remark-mdx-frontmatter": "4.0.0",
|
"remark-mdx-frontmatter": "4.0.0",
|
||||||
"tailwindcss": "3.4.0",
|
"tailwindcss": "3.4.1",
|
||||||
"yaml-loader": "0.8.0"
|
"yaml-loader": "0.8.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
/*
|
||||||
|
* This file is auto-generated.
|
||||||
|
* Any manual changes will be overwritten.
|
||||||
|
*/
|
||||||
import { Aaron as aaron } from '@freesewing/aaron'
|
import { Aaron as aaron } from '@freesewing/aaron'
|
||||||
import { Albert as albert } from '@freesewing/albert'
|
import { Albert as albert } from '@freesewing/albert'
|
||||||
import { Bee as bee } from '@freesewing/bee'
|
import { Bee as bee } from '@freesewing/bee'
|
||||||
|
@ -24,7 +28,6 @@ import { Huey as huey } from '@freesewing/huey'
|
||||||
import { Hugo as hugo } from '@freesewing/hugo'
|
import { Hugo as hugo } from '@freesewing/hugo'
|
||||||
import { Jaeger as jaeger } from '@freesewing/jaeger'
|
import { Jaeger as jaeger } from '@freesewing/jaeger'
|
||||||
import { Lucy as lucy } from '@freesewing/lucy'
|
import { Lucy as lucy } from '@freesewing/lucy'
|
||||||
import { Lumira as lumira } from '@freesewing/lumira'
|
|
||||||
import { Lunetius as lunetius } from '@freesewing/lunetius'
|
import { Lunetius as lunetius } from '@freesewing/lunetius'
|
||||||
import { Noble as noble } from '@freesewing/noble'
|
import { Noble as noble } from '@freesewing/noble'
|
||||||
import { Octoplushy as octoplushy } from '@freesewing/octoplushy'
|
import { Octoplushy as octoplushy } from '@freesewing/octoplushy'
|
||||||
|
@ -49,6 +52,7 @@ import { Walburga as walburga } from '@freesewing/walburga'
|
||||||
import { Waralee as waralee } from '@freesewing/waralee'
|
import { Waralee as waralee } from '@freesewing/waralee'
|
||||||
import { Yuri as yuri } from '@freesewing/yuri'
|
import { Yuri as yuri } from '@freesewing/yuri'
|
||||||
import { Otis as otis } from '@freesewing/otis'
|
import { Otis as otis } from '@freesewing/otis'
|
||||||
|
import { Lumira as lumira } from '@freesewing/lumira'
|
||||||
|
|
||||||
const designs = {
|
const designs = {
|
||||||
aaron,
|
aaron,
|
||||||
|
@ -77,7 +81,6 @@ const designs = {
|
||||||
hugo,
|
hugo,
|
||||||
jaeger,
|
jaeger,
|
||||||
lucy,
|
lucy,
|
||||||
lumira,
|
|
||||||
lunetius,
|
lunetius,
|
||||||
noble,
|
noble,
|
||||||
octoplushy,
|
octoplushy,
|
||||||
|
@ -102,6 +105,7 @@ const designs = {
|
||||||
waralee,
|
waralee,
|
||||||
yuri,
|
yuri,
|
||||||
otis,
|
otis,
|
||||||
|
lumira,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useDesign = (design) => (designs[design] ? designs[design] : false)
|
export const useDesign = (design) => (designs[design] ? designs[design] : false)
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
},
|
},
|
||||||
"peerDependencies": {},
|
"peerDependencies": {},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bugsnag/js": "7.22.2",
|
"@bugsnag/js": "7.22.3",
|
||||||
"@bugsnag/plugin-react": "7.19.0",
|
"@bugsnag/plugin-react": "7.19.0",
|
||||||
"@mdx-js/mdx": "^3.0.0",
|
"@mdx-js/mdx": "^3.0.0",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
"next": "14.0.4",
|
"next": "14.0.4",
|
||||||
"ora": "8.0.1",
|
"ora": "8.0.1",
|
||||||
"react-dropzone": "14.2.3",
|
"react-dropzone": "14.2.3",
|
||||||
"react-hotkeys-hook": "4.4.1",
|
"react-hotkeys-hook": "4.4.3",
|
||||||
"react-instantsearch-dom": "6.40.4",
|
"react-instantsearch-dom": "6.40.4",
|
||||||
"react-swipeable": "7.0.1",
|
"react-swipeable": "7.0.1",
|
||||||
"react-timeago": "7.2.0",
|
"react-timeago": "7.2.0",
|
||||||
|
@ -69,10 +69,10 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "10.4.16",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"postcss": "8.4.32",
|
"postcss": "8.4.33",
|
||||||
"remark-extract-frontmatter": "3.2.0",
|
"remark-extract-frontmatter": "3.2.0",
|
||||||
"remark-mdx-frontmatter": "4.0.0",
|
"remark-mdx-frontmatter": "4.0.0",
|
||||||
"tailwindcss": "3.4.0",
|
"tailwindcss": "3.4.1",
|
||||||
"yaml-loader": "0.8.0"
|
"yaml-loader": "0.8.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
|
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
|
||||||
"@tailwindcss/typography": "0.5.10",
|
"@tailwindcss/typography": "0.5.10",
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "10.4.16",
|
||||||
"axios": "1.6.3",
|
"axios": "1.6.5",
|
||||||
"d3-dispatch": "3.0.1",
|
"d3-dispatch": "3.0.1",
|
||||||
"d3-drag": "3.0.0",
|
"d3-drag": "3.0.0",
|
||||||
"d3-selection": "3.0.0",
|
"d3-selection": "3.0.0",
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
"echarts": "5.4.3",
|
"echarts": "5.4.3",
|
||||||
"echarts-for-react": "3.0.2",
|
"echarts-for-react": "3.0.2",
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
"i18next": "23.7.13",
|
"i18next": "23.7.15",
|
||||||
"jotai": "2.6.1",
|
"jotai": "2.6.1",
|
||||||
"jotai-location": "0.5.2",
|
"jotai-location": "0.5.2",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
|
@ -64,13 +64,13 @@
|
||||||
"lodash.set": "4.3.2",
|
"lodash.set": "4.3.2",
|
||||||
"mustache": "4.2.0",
|
"mustache": "4.2.0",
|
||||||
"next": "14.0.4",
|
"next": "14.0.4",
|
||||||
"next-i18next": "15.1.2",
|
"next-i18next": "15.2.0",
|
||||||
"pdfkit": "0.14.0",
|
"pdfkit": "0.14.0",
|
||||||
"postcss-for": "2.1.1",
|
"postcss-for": "2.1.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-copy-to-clipboard": "5.1.0",
|
"react-copy-to-clipboard": "5.1.0",
|
||||||
"react-hotkeys-hook": "4.4.1",
|
"react-hotkeys-hook": "4.4.3",
|
||||||
"react-i18next": "13.5.0",
|
"react-i18next": "13.5.0",
|
||||||
"react-dropzone": "14.2.3",
|
"react-dropzone": "14.2.3",
|
||||||
"react-swipeable": "7.0.1",
|
"react-swipeable": "7.0.1",
|
||||||
|
@ -79,13 +79,13 @@
|
||||||
"remark-gfm": "4.0.0",
|
"remark-gfm": "4.0.0",
|
||||||
"remark-frontmatter": "5.0.0",
|
"remark-frontmatter": "5.0.0",
|
||||||
"remark-mdx-frontmatter": "4.0.0",
|
"remark-mdx-frontmatter": "4.0.0",
|
||||||
"remark-smartypants": "2.0.0",
|
"remark-smartypants": "2.1.0",
|
||||||
"slugify": "^1.6.6",
|
"slugify": "^1.6.6",
|
||||||
"svg-to-pdfkit": "https://git@github.com/eriese/SVG-to-PDFKit",
|
"svg-to-pdfkit": "https://git@github.com/eriese/SVG-to-PDFKit",
|
||||||
"tailwindcss": "3.4.0",
|
"tailwindcss": "3.4.1",
|
||||||
"tlds": "1.248.0",
|
"tlds": "1.248.0",
|
||||||
"use-local-storage-state": "19.1.0",
|
"use-local-storage-state": "19.1.0",
|
||||||
"web-worker": "1.2.0"
|
"web-worker": "1.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -80,7 +80,12 @@ export const DesignCard = ({ name, lineDrawing = false }) => {
|
||||||
<button
|
<button
|
||||||
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
|
||||||
|
>
|
||||||
<h1>{t(`designs:${name}.t`)}</h1>
|
<h1>{t(`designs:${name}.t`)}</h1>
|
||||||
<DesignInfo design={name} modal />
|
<DesignInfo design={name} modal />
|
||||||
</ModalWrapper>
|
</ModalWrapper>
|
||||||
|
|
|
@ -32,28 +32,25 @@ export const Tabs = ({ tabs = '', active = 0, children, withModal = false }) =>
|
||||||
}`
|
}`
|
||||||
|
|
||||||
return withModal && activeTab === tabId ? (
|
return withModal && activeTab === tabId ? (
|
||||||
<div className={`flex flex-row justify-between w-1/${tablist.length}`}>
|
<button
|
||||||
<button key={tabId} className={btnClasses} onClick={() => setActiveTab(tabId)}>
|
key={tabId}
|
||||||
{title}
|
className={btnClasses}
|
||||||
</button>
|
onClick={() =>
|
||||||
<button
|
setModal(
|
||||||
className={`${btnClasses} px-0`}
|
<ModalWrapper
|
||||||
onClick={() =>
|
flex="col"
|
||||||
setModal(
|
justify="top lg:justify-center"
|
||||||
<ModalWrapper
|
slideFrom="right"
|
||||||
flex="col"
|
fullWidth
|
||||||
justify="top lg:justify-center"
|
>
|
||||||
slideFrom="right"
|
{childrenWithTabSetter}
|
||||||
fullWidth
|
</ModalWrapper>
|
||||||
>
|
)
|
||||||
{childrenWithTabSetter}
|
}
|
||||||
</ModalWrapper>
|
>
|
||||||
)
|
<span className="pr-2">{title}</span>
|
||||||
}
|
<KioskIcon className="w-6 h-6 hover:text-secondary" />
|
||||||
>
|
</button>
|
||||||
<KioskIcon className="w-6 h-6 hover:text-secondary" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<button key={tabId} className={btnClasses} onClick={() => setActiveTab(tabId)}>
|
<button key={tabId} className={btnClasses} onClick={() => setActiveTab(tabId)}>
|
||||||
{title}
|
{title}
|
||||||
|
|
|
@ -57,7 +57,13 @@ export const ModalWrapper = ({
|
||||||
? `lg:opacity-0 ${slideClasses[slideFrom]} lg:translate-x-0 lg:translate-y-0`
|
? `lg:opacity-0 ${slideClasses[slideFrom]} lg:translate-x-0 lg:translate-y-0`
|
||||||
: 'opacity-100 translate-none'
|
: 'opacity-100 translate-none'
|
||||||
|
|
||||||
const stopClick = (evt) => evt.stopPropagation()
|
const stopClick = (evt) => {
|
||||||
|
/*
|
||||||
|
* Do not keep modal open for links (with a href)
|
||||||
|
* but do keep it open for buttons (like a new modal context)
|
||||||
|
*/
|
||||||
|
if (!evt.target.attributes.href) evt.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { i18n as legend } from '@freesewing/legend'
|
||||||
import { i18n as lucy } from '@freesewing/lucy'
|
import { i18n as lucy } from '@freesewing/lucy'
|
||||||
import { i18n as lunetius } from '@freesewing/lunetius'
|
import { i18n as lunetius } from '@freesewing/lunetius'
|
||||||
import { i18n as magde } from '@freesewing/magde'
|
import { i18n as magde } from '@freesewing/magde'
|
||||||
|
import { i18n as naomiwu } from '@freesewing/naomiwu'
|
||||||
import { i18n as noble } from '@freesewing/noble'
|
import { i18n as noble } from '@freesewing/noble'
|
||||||
import { i18n as octoplushy } from '@freesewing/octoplushy'
|
import { i18n as octoplushy } from '@freesewing/octoplushy'
|
||||||
import { i18n as onyx } from '@freesewing/onyx'
|
import { i18n as onyx } from '@freesewing/onyx'
|
||||||
|
@ -90,6 +91,7 @@ export const designs = {
|
||||||
lucy,
|
lucy,
|
||||||
lunetius,
|
lunetius,
|
||||||
magde,
|
magde,
|
||||||
|
naomiwu,
|
||||||
noble,
|
noble,
|
||||||
octoplushy,
|
octoplushy,
|
||||||
onyx,
|
onyx,
|
||||||
|
|
|
@ -49,14 +49,14 @@
|
||||||
"rehype-highlight": "7.0.0",
|
"rehype-highlight": "7.0.0",
|
||||||
"remark-frontmatter": "5.0.0",
|
"remark-frontmatter": "5.0.0",
|
||||||
"remark-mdx-frontmatter": "4.0.0",
|
"remark-mdx-frontmatter": "4.0.0",
|
||||||
"remark-smartypants": "2.0.0",
|
"remark-smartypants": "2.1.0",
|
||||||
"slugify": "^1.6.6",
|
"slugify": "^1.6.6",
|
||||||
"svg-to-pdfkit": "https://git@github.com/eriese/SVG-to-PDFKit",
|
"svg-to-pdfkit": "https://git@github.com/eriese/SVG-to-PDFKit",
|
||||||
"tlds": "1.248.0",
|
"tlds": "1.248.0",
|
||||||
"to-vfile": "8.0.0",
|
"to-vfile": "8.0.0",
|
||||||
"unist-util-visit": "5.0.0",
|
"unist-util-visit": "5.0.0",
|
||||||
"use-local-storage-state": "19.1.0",
|
"use-local-storage-state": "19.1.0",
|
||||||
"web-worker": "1.2.0"
|
"web-worker": "1.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"recursive-readdir": "^2.2.3",
|
"recursive-readdir": "^2.2.3",
|
||||||
|
|
|
@ -73,10 +73,10 @@
|
||||||
@apply pl-2 lg:pl-4 list-decimal list-inside text-base-content;
|
@apply pl-2 lg:pl-4 list-decimal list-inside text-base-content;
|
||||||
}
|
}
|
||||||
.mdx code {
|
.mdx code {
|
||||||
@apply bg-neutral-content px-2 rounded text-neutral font-mono font-bold;
|
@apply bg-base-300 px-1.5 text-base-content font-mono font-medium bg-opacity-10 py-0.5 border-base-content rounded border;
|
||||||
}
|
}
|
||||||
.mdx pre code {
|
.mdx pre code {
|
||||||
@apply bg-inherit;
|
@apply bg-inherit border-0;
|
||||||
}
|
}
|
||||||
.mdx a.heading-autolink {
|
.mdx a.heading-autolink {
|
||||||
color: currentColor;
|
color: currentColor;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue