From 18245aec34be1dbe9c64c4aed583f9f718b9bc92 Mon Sep 17 00:00:00 2001 From: anna-puk <100537439+anna-puk@users.noreply.github.com> Date: Sat, 24 Sep 2022 13:12:40 +0200 Subject: [PATCH] NOT WORKING: restore unice from older commit does not work, but good to have on hand to diff with --- config/software/designs.json | 7 + designs/unice/CHANGELOG.md | 15 + designs/unice/README.md | 284 +++++++++++++++++++ designs/unice/build.mjs | 50 ++++ designs/unice/config/index.js | 62 +++++ designs/unice/data.mjs | 4 + designs/unice/example/.babelrc | 10 + designs/unice/example/README.md | 96 +++++++ designs/unice/example/netlify.toml | 9 + designs/unice/example/package.json | 56 ++++ designs/unice/example/public/favicon.ico | Bin 0 -> 12053 bytes designs/unice/example/public/index.html | 41 +++ designs/unice/example/public/layout.css | 1 + designs/unice/example/public/manifest.json | 15 + designs/unice/example/src/App.js | 45 +++ designs/unice/example/src/index.js | 12 + designs/unice/example/src/layout.css | 273 ++++++++++++++++++ designs/unice/example/src/pattern | 1 + designs/unice/example/src/serviceWorker.js | 123 ++++++++ designs/unice/package.json | 67 +++++ designs/unice/src/back.mjs | 42 +++ designs/unice/src/front.mjs | 309 +++++++++++++++++++++ designs/unice/src/gusset.mjs | 4 + designs/unice/src/index.mjs | 14 + designs/unice/tests/shared.test.mjs | 16 ++ 25 files changed, 1556 insertions(+) create mode 100644 designs/unice/CHANGELOG.md create mode 100644 designs/unice/README.md create mode 100644 designs/unice/build.mjs create mode 100644 designs/unice/config/index.js create mode 100644 designs/unice/data.mjs create mode 100644 designs/unice/example/.babelrc create mode 100644 designs/unice/example/README.md create mode 100644 designs/unice/example/netlify.toml create mode 100644 designs/unice/example/package.json create mode 100644 designs/unice/example/public/favicon.ico create mode 100644 designs/unice/example/public/index.html create mode 100644 designs/unice/example/public/layout.css create mode 100644 designs/unice/example/public/manifest.json create mode 100644 designs/unice/example/src/App.js create mode 100644 designs/unice/example/src/index.js create mode 100644 designs/unice/example/src/layout.css create mode 100644 designs/unice/example/src/pattern create mode 100644 designs/unice/example/src/serviceWorker.js create mode 100644 designs/unice/package.json create mode 100644 designs/unice/src/back.mjs create mode 100644 designs/unice/src/front.mjs create mode 100644 designs/unice/src/gusset.mjs create mode 100644 designs/unice/src/index.mjs create mode 100644 designs/unice/tests/shared.test.mjs diff --git a/config/software/designs.json b/config/software/designs.json index 75abc902887..03ad76be50b 100644 --- a/config/software/designs.json +++ b/config/software/designs.json @@ -284,6 +284,13 @@ "difficulty": 1, "tags": [ "tops", "historic" ] }, + "unice": { + "description": "A FreeSewing pattern for a basic, highly-customizable underwear pattern", + "code": [ "Anna Puk", "Natalia Sayang" ], + "design": [ "Anna Puk", "Natalia Sayang" ], + "difficulty": 1, + "tags": [ "bottoms", "underwear" ] + }, "ursula": { "description": "A FreeSewing pattern for a basic, highly-customizable underwear pattern", "code": "Natalia Sayang", diff --git a/designs/unice/CHANGELOG.md b/designs/unice/CHANGELOG.md new file mode 100644 index 00000000000..6b458471bea --- /dev/null +++ b/designs/unice/CHANGELOG.md @@ -0,0 +1,15 @@ +# Change log for: @freesewing/unice + + +## 2.21.0 (2022-06-27) + +### Added + + - Unice is an underwear pattern + + +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. + diff --git a/designs/unice/README.md b/designs/unice/README.md new file mode 100644 index 00000000000..3c02b12a2d2 --- /dev/null +++ b/designs/unice/README.md @@ -0,0 +1,284 @@ +![FreeSewing](https://static.freesewing.org/banner.png) +

@freesewing/unice on NPM + License: MIT + Code quality on DeepScan + Open issues tagged pkg:unice + All Contributors +

Follow @freesewing_org on Twitter + Chat with us on Discord + Become a FreeSewing Patron + Follow @freesewing_org on Twitter +

+ +# @freesewing/unice + +A FreeSewing pattern for a basic, highly-customizable underwear pattern + + + + +> #### Note: Version 3 is a work in progress +> +> We are working on a new major version (v3) but it is not ready for prime-time. +> For production use, please refer to our v2 packages (the `latest` on NPM) +> or [the `v2` branch in our monorepo](https://github.com/freesewing/freesewing/tree/v2). + +## What am I looking at? πŸ€” + +This repository is our *monorepo* holding all our NPM designs, plugins, other NPM packages, and (web)sites. + +This folder holds: @freesewing/unice + +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: +> +> [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/freesewing/freesewing) +> +> We recommend that you fork our repository and then +> put `gitpod.io/# 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 +our sewing patterns adapted to your measurements. + +If you're a developer, our documentation is on [freesewing.dev](https://freesewing.dev/). +Our [core library](https://freesewing.dev/reference/api/) is a *batteries-included* toolbox +for parametric design of sewing patterns. But we also provide 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 +``` + +Or, consult our getting started guides +for [Linux](https://freesewing.dev/tutorials/getting-started-linux/), +[MacOS](https://freesewing.dev/tutorials/getting-started-mac/), +or [Windows](https://freesewing.dev/tutorials/getting-started-windows/). + +We also have a [pattern design tutorial](https://freesewing.dev/tutorials/pattern-design/) that +walks you through your first parametric design, +and [a friendly community](https://freesewing.org/community/where/) with +people who can help you when you get stuck. + +## Support FreeSewing: Become a patron πŸ₯° + +FreeSewing is an open source project run by a community, +and financially supported by our patrons. + +If you feel what we do is worthwhile, and you can spend a few coind without +hardship, then you should [join us and become a patron](https://freesewing.org/community/join). + +## Links πŸ‘©β€πŸ’» + + - πŸ’» Makers website: [freesewing.org](https://freesewing.org) + - πŸ’» Developers website: [freesewing.dev](https://freesewing.dev) + - πŸ’¬ Chat: On Discord via [discord.freesewing.org](https://discord.freesewing.org/) + - βœ… Todo list/Kanban board: On Github via [todo.freesewing.org](https://todo.freesewing.org/) + - 🐦 Twitter: [@freesewing_org](https://twitter.com/freesewing_org) + - πŸ“· Instagram: [@freesewing_org](https://instagram.com/freesewing_org) + +## 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 🀯 + +Our [chatrooms on Discord](https://chat.freesewing.org/) are the best place to ask questions, +share your feedback, or just hang out. + +If you want to report a problem, please [create an issue](https://github.com/freesewing/freesewing/issues/new). + + + +## Contributors ✨ + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Adam Tomkins

πŸ“–

Alexandre Ignjatovic

πŸ’»

AlfaLyr

πŸ’» πŸ”Œ 🎨

Andrew James

πŸ“–

Anneke

πŸ“– 🌍

Annie Kao

πŸ“–

Anternative

πŸ“–

Anthony

πŸ’¬

Ari Grayzel-student

πŸ’»

BenJamesBen

πŸ’» πŸ“–

Cameron Dubas

πŸ“–

Carsten Biebricher

πŸ“–

Cathy Zoller

πŸ“–

Chantal Lapointe

🌍

Damien PIQUET

πŸ’»

Darigov Research

πŸ“– πŸ€”

Elena FdR

πŸ“– πŸ“

Emmanuel Nyachoke

πŸ’» πŸ“–

Enoch Riese

πŸ’»

EvEkSwed

🌍

Fantastik-Maman

🌍

Forrest O.

πŸ“–

FrΓ©dΓ©ric

🌍

Glenn Matthews

πŸ“–

Greg Sadetsky

πŸ“–

Igor Couto

πŸ›

Ikko Ashimine

πŸ“–

Irapeke

🌍

Jacek Sawoszczuk

πŸ“–

Jason Williams

πŸ“–

Jeremy Jackson

πŸ’»

Joe Schofield

πŸ“–

Joebidido

🌍

Joost De Cock

🚧

Josh Essman

πŸ“–

Kake

πŸ“–

Kapunahele Wong

πŸ“–

Karen

πŸ“– πŸ“‹

Katie McGinley

πŸ“–

Kieran Klaassen

πŸ’»

Kittycatou

🌍

Kris

πŸ“–

Kristin Ruben

πŸ’»

Loudepeuter

🌍

Lucian

πŸ“‹

Marcus

🌍

Martin Tribo

πŸ“–

Nadege Michel

⚠️ πŸ“–

Natalia

πŸ’» 🎨 πŸ“

Nathan Yergler

πŸ“–

Nick Dower

πŸ“– πŸ’» πŸ›

Nikhil Chelliah

πŸ“–

OysteinHoiby

πŸ’»

Patrick Forringer

πŸ”Œ

Paul

πŸ“– πŸ“ 🌍

Phillip Thelen

πŸ’»

Pixieish

πŸ“–

Prof. dr. Sorcha NΓ­ Dhubhghaill

πŸ“–

Quentin FELIX

πŸ’» 🎨

Rik Hekker

πŸ›

Sam Livingston-Gray

πŸ“–

Sanne

πŸ’» πŸ“–

Sara Latorre

🌍

SeaZeeZee

πŸ“– πŸ’»

SimonbJohnson

πŸ›

Slylele

πŸ“– 🌍

Soazillon

🌍

SoneaTheBest

🌍

Stefan Sydow

🌍 πŸ“– πŸ’»

TrΓ­ona

πŸ“–

Unmutual

πŸ“–

Wouter van Wageningen

πŸ’» 🎨 πŸ”§

amysews

πŸ“–

anna-puk

πŸ’»

beautifulsummermoon

🌍

berce

πŸ“–

biou

πŸ’»

bobgeorgethe3rd

πŸ’» πŸ“– 🎨

brmlyklr

πŸ“–

chri5b

πŸ’» ⚠️

dingcycle

🌍

drowned-in-books

πŸ’¬

econo202

πŸ“–

ericamattos

🌍

fightingrabbit

πŸ’»

gaylyndie

πŸ“–

grimlokason

πŸ’»

hellgy

🎨

jackseye

πŸ“–

marckiesel

🌍

mesil

πŸ›

starfetch

πŸ’» πŸ“– 🌍 🎨

ttimearl

πŸ–‹

tuesgloomsday

πŸ“–

valadaptive

πŸ’»

viocky

🌍

woolishboy

πŸ’»

yc

🌍
+ + + + + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! + diff --git a/designs/unice/build.mjs b/designs/unice/build.mjs new file mode 100644 index 00000000000..c5581c1e4a2 --- /dev/null +++ b/designs/unice/build.mjs @@ -0,0 +1,50 @@ +/* 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 +let result +(async () => { + result = await esbuild.build(options).catch(() => process.exit(1)) + + if (process.env.VERBOSE) { + const info = await esbuild.analyzeMetafile(result.metafile) + console.log(info) + } + + // Also build a version that has all dependencies bundled + // This makes it easy to run tests + await esbuild + .build({ + ...options, + minify: false, + keepNames: true, + sourcemap: false, + outfile: 'tests/dist/index.mjs', + format: 'esm', + external: [], + }) + .catch(() => process.exit(1)) + +})() diff --git a/designs/unice/config/index.js b/designs/unice/config/index.js new file mode 100644 index 00000000000..25bc838e8cf --- /dev/null +++ b/designs/unice/config/index.js @@ -0,0 +1,62 @@ +import { config as ursulaConfig } from '@freesewing/ursula' +import pkg from '../package.json' assert { type: 'json' } + +const { version } = pkg +const design = ['Anna Puk', 'Natalia Sayang'] + +const config = { + ...ursulaConfig, + version, + design, + code: design, + name: 'unice', + inject: { + front: 'ursulaFront', + back: 'ursulaBack', + gusset: 'ursulaGusset', + front2: 'front', + back2: 'back', + gusset2: 'gusset', + }, + hide: ['ursulaBack', 'ursulaFront', 'ursulaGusset','front', 'back', 'gusset'], + parts: ['front','back','gusset','elastic','front2','back2','gusset2'], + optionalMeasurements: ['crossSeam','crossSeamFront'], + measurements: ['waist', 'seat', 'waistToSeat', 'waistToUpperLeg','hips','waistToHips'], + optionGroups: { + ...ursulaConfig.optionGroups, + fit: [ + 'fabricStretchX', + 'fabricStretchY', + 'adjustStretch', + 'elasticStretch', + 'useCrossSeam', + 'gussetWidth', + 'gussetLength' + ], + }, + dependencies: { + back: 'front', + gusset: 'back', + elastic: 'gusset', + front2: 'elastic', + back2: 'elastic', + gusset2: 'elastic', + }, + options: { + ...ursulaConfig.options, + gussetShift: 0.015, // fraction of seat circumference - could be an advanced option? + gussetWidth: { pct: 7.2, min: 2, max: 12 }, // Gusset width in relation to waist-to-upperleg + fabricStretchX: { pct: 15, min: 0, max: 100 }, // horizontal stretch (range set wide for beta testing) + fabricStretchY: {pct: 0, min: 0, max: 100 }, // vertical stretch (range set wide for beta testing) + rise: { pct: 60, min: 30, max: 100 }, // extending rise beyond 100% would require adapting paths.sideLeft! + legOpening: { pct: 45, min: 5, max: 85 }, + // booleans + useCrossSeam: { bool: true }, + adjustStretch: {bool: true}, // to not stretch fabric to the limits + } +} + +//delete config.options.fabricStretch + +export default config + diff --git a/designs/unice/data.mjs b/designs/unice/data.mjs new file mode 100644 index 00000000000..510883477b0 --- /dev/null +++ b/designs/unice/data.mjs @@ -0,0 +1,4 @@ +// This file is auto-generated | All changes you make will be overwritten. +export const name = "@freesewing/unice" +export const version = "3.0.0-alpha.0" +export const data = { name, version } diff --git a/designs/unice/example/.babelrc b/designs/unice/example/.babelrc new file mode 100644 index 00000000000..6e3090a4956 --- /dev/null +++ b/designs/unice/example/.babelrc @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["prismjs", { + "languages": ["javascript", "css", "markup"], + "plugins": ["line-numbers"], + "theme": "twilight", + "css": true + }] + ] +} diff --git a/designs/unice/example/README.md b/designs/unice/example/README.md new file mode 100644 index 00000000000..73d3153ee6f --- /dev/null +++ b/designs/unice/example/README.md @@ -0,0 +1,96 @@ +

+Freesewing logo +
+FreeSewing v2 +

+

A JavaScript library for made-to-measure sewing patterns

+

Follow @freesewing_org on Twitter + Chat with us on Gitter + Become a FreeSewing Patron + Follow @freesewing_org on Twitter + +

+ +# unice example + +This project was bootstrapped with [Create Freesewing Pattern](https://en.freesewing.dev/create-freesewing-pattern): + +```js +npm init freesewing-pattern +``` + +This example folder is part of the local development environment. +It is **not** part of the pattern's source code. + +To run this example, follow these steps: + + - In the folder above this one, run: `yarn start` (or `npm start`) + - Then, in new terminal, run the same command in this folder: `yarn start` (or `npm start`) + +This will spin up the development environment, similar to [our online demo](https://unice.freesewing.dev/). + +## About FreeSewing πŸ€” + +Where the world of makers and developers collide, that's where you'll find FreeSewing. + +Our [core library](https://freesewing.dev/en/freesewing) is a *batteries-included* toolbox +for parametric design of sewing patterns. It's a modular system (check our list +of [plugins](https://freesewing.dev/en/plugins) and getting started is as simple as: + +```bash +npm init freesewing-pattern +``` + +The [getting started] section on [freesewing.dev](https://freesewing.dev/) is a good +entrypoint to our documentation, but you'll find a lot more there, including +our [API documentation](https://freesewing.dev/en/freesewing/api), +as well as [examples](https://freesewing.dev/en/freesewing/examples), +and [best practices](https://freesewing.dev/en/do). + +If you're a maker, checkout [freesewing.org](https://freesewing/) where you can generate +our sewing patterns adapted to your measurements. + +## Support FreeSewing: Become a patron πŸ₯° + +FreeSewing is an open source project run by a community, +and financially supported by our patrons. + +If you feel what we do is worthwhile, you too +should [become a patron](https://freesewing.org/patrons/join). + +## Links πŸ‘©β€πŸ’» + + - πŸ’» Makers website: [freesewing.org](https://freesewing.org) + - πŸ’» Developers website: [freesewing.dev](https://freesewing.org) + - πŸ’¬ Chat: [gitter.im/freesewing](https://gitter.im/freesewing/freesewing) + - 🐦 Twitter: [@freesewing_org](https://twitter.com/freesewing_org) + - πŸ“· Instagram: [@freesewing_org](https://instagram.com/freesewing_org) + +## 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 🀯 + +Our [chatroom on Gitter](https://gitter.im) is the best place to ask questions, +share your feedback, or just hang out. + +If you want to report a problem, please [create an issue](https://github.com/freesewing/freesewing/issues/new). + diff --git a/designs/unice/example/netlify.toml b/designs/unice/example/netlify.toml new file mode 100644 index 00000000000..9890e6c62f2 --- /dev/null +++ b/designs/unice/example/netlify.toml @@ -0,0 +1,9 @@ +[build] + base = "designs/unice/example" + publish = "build" + command = "npm run build" + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 diff --git a/designs/unice/example/package.json b/designs/unice/example/package.json new file mode 100644 index 00000000000..77774ed36a3 --- /dev/null +++ b/designs/unice/example/package.json @@ -0,0 +1,56 @@ +{ + "name": "unice", + "homepage": "https://unice.freesewing.dev/", + "version": "", + "private": true, + "dependencies": { + "@fontsource/permanent-marker": "latest", + "@fontsource/roboto-mono": "latest", + "@fontsource/ubuntu": "latest", + "@freesewing/components": "latest", + "@freesewing/core": "latest", + "@freesewing/css-theme": "latest", + "@freesewing/i18n": "latest", + "@freesewing/models": "latest", + "@freesewing/mui-theme": "latest", + "@freesewing/pattern-info": "latest", + "@freesewing/plugin-bundle": "latest", + "@freesewing/plugin-theme": "latest", + "@freesewing/plugin-i18n": "latest", + "@freesewing/plugin-svgattr": "latest", + "@freesewing/utils": "latest", + "@material-ui/core": "^4.11.4", + "@material-ui/icons": "^4.11.2", + "@material-ui/lab": "^v4.0.0-alpha.57", + "prismjs": "1.25.0", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-intl": "^5.18.0", + "react-scripts": "^4.0.3", + "react-error-overlay": "6.0.9", + "file-saver": "^2.0.5", + "react-markdown": "6.0.2", + "source-map-explorer": "^2.5.2" + }, + "scripts": { + "analyze": "source-map-explorer 'build/static/js/*.js'", + "size": "source-map-explorer 'build/static/js/*.js' --tsv --no-root", + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": [ + "defaults" + ], + "devDependencies": { + "babel-plugin-prismjs": "2.0.1", + "react-error-overlay": "6.0.9" + }, + "resolutions": { + "react-error-overlay": "6.0.9" + } +} diff --git a/designs/unice/example/public/favicon.ico b/designs/unice/example/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..95061a260f10f9f0fb6464069a6d65df8dc8a471 GIT binary patch literal 12053 zcmZQzU}Ruq00Bk@1&0563=Con3=EwCe(tgbC?LeQ2nsxfK}sMrrE6L9$cQ!&TshX)29^&uC!fvqkJK9 zLAyhI<7ZYjju^#)tp`GxrgMKezW?O;FCrE(3z+?`yZx}M{FU}gGv~;W^?mp6`ajTY zlxOu)_+kC=zxkt?6(1{)d@Gs46zQK}-)P5V&b>#&AUL7%fK;O{lQoN02gA&TO!Mz* zeb{}VsPR2Z8pj^h4?PF&GF|7G!+TW8_tRe1Zz35A0l}Kx({!W%t(>95vUin(ZevVi z8IwBaotFDwyB%gelibe9bNv0o-UG_h)IP>B?PZk{`yrE7IFpz0yU^4Cu}dQHx*I$m zWH>COxSYZFH^ZghUzajYmPZu2CUEioSWeom;A2j>R~>6xs8@z zpZ@*9(YT#;+wqVOPfZsJKWj2)>%TGMwydO;KZpPBpMpt28_gV^3ZM-IK= zGEy#@b)fT3tGCiQYg6o07luMfq{F)x1;@!)yr=ydidO-Pav&!EqF1~?X*k&UB=FAssSNz~{(tW} zrf%(I)tfM*-9;yi$;L*!Zf5T{KJgzca+6}dYJ@S_>=F8>b;9%i#8z#Sh!b87?c#^@ zrDI~aqqN1=e28SKk$o_6%Srv)1-2*S{$2RZa>MY%;f)_oADPE5n3UwmWv;T{K~bAg z&hOoC`;8A=xHj=0mRrM65y4qsT5|JmFRR+5lTM2tUVg}X{;~Wa{pv4wyVS&V3@*BG z-db)fYuUg5>&wY^ij{LqHm0`7zrOHq&R<5IKf8^7&+E-RK5s`7pOtCqlc!HN8XURt zCcmTZ`PTJ70WChPq9_}00=E}r#~=ATIpj||VfeD34eXtsvsk?NnD zE1qd5GbV7@^nTFi_TXuWSNj=rbW1D`^V$ggZA^>w{|MFYNMv_zez{6svHt~Ey?W!( zJvSw#rYJK{S=-Q|#ckhjo&0qbP&{T{4oFDrd{tv?_KCoF_?XOV*C9s`x&0j z-?LEiWWux_nU#D2HiwonsQkUmzo%1DPx0`vbZsHQbuv8dAH4P7aopR()4##@L22XU z3-ueM;(43i{;+P++$*7{7`dR{RHQrCJ-*|*qg?Uw0|t$=S=ttaR<66#{OQ&KW!vTZ zO|GhaU`wkA(9*HCi&y{P%M>4^IjLh^;L9VQ3?5CCJ3im!^0rTGX%!9Z2c%SIwp4TR zxQD!~O^~rrdAi^9QMThR(S|i2=O2=u{!nnA$PM3_UzW@=kzS$XUscA#_WX-IE1&ee zJv{mwJhzHI7VKLx-*Zo<^WpRI)6(}&^Zm`hpERpf{Kla}qFiTK1z+zHuvz`(NBTx4 zj=DSlEydPcNZ9F6{lR#T%m=5nt}#k7HLMq+5+u39Rv1WRt7q;!FBBp0KxIMR8iuB~ ze|FDUx!1YfpXJrbug)uc!*chDUnrG1Q`hi7i=ooKx|daJO6m7@A=U|vI=h}T-B_3@ zGr5H&obd^#PGTdMYTgoc?SK3C9azzz*_eO9v8z?Df$Kqq-cMfLd*<7o9h!A&^})%E zyZF|Kzc|6AFys6G*%1?*x}>Ppw$kzZ0?8jT*Dy3m{*yl6BogIu`mM#{ z1i|?ZikAwTKddp|tZY!hrQrS`TWm?dW2w0bg52v@AGpO}^IUrcbHYRJ2}~2zk9dhK z3V1BJd9rBze9Z#qx?i(*oNH>H)T-~mwSas1e>Wxh1>0sO2-Y8PXZ#Q@vVnFb`~;aa9CwvR!xfjgo>X`;ZDlU^G>{l9+q?bW=6%-jJg1_l!Y1hp0B z*7To0ta;LD#yLj|hPKTgT$svLtRg%0AD9??TlUy;xumgp9^ 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 literal 0 HcmV?d00001 diff --git a/designs/unice/example/public/index.html b/designs/unice/example/public/index.html new file mode 100644 index 00000000000..af182fd3cc0 --- /dev/null +++ b/designs/unice/example/public/index.html @@ -0,0 +1,41 @@ + + + + + + + + + + + + unice + + + +
+ + + diff --git a/designs/unice/example/public/layout.css b/designs/unice/example/public/layout.css new file mode 100644 index 00000000000..c62502f9791 --- /dev/null +++ b/designs/unice/example/public/layout.css @@ -0,0 +1 @@ +div.layout-wrapper{width:100%;margin:0;padding:0;background-color:red;background:#f8f9fa;background:linear-gradient(90deg, #f1f3f5 0%, #f1f3f5 25%, #f8f9fa 26%, #f8f9fa 100%)}div.layout-wrapper div.layout{display:flex;max-width:1600px;margin:auto;padding:0;flex-direction:row;flex-wrap:nowrap;justify-content:space-between;background-color:#f8f9fa;min-height:calc(100vh - 64px)}div.layout-wrapper div.layout>aside{width:33%;background:#f1f3f5;border-right:2px solid #dee2e6}div.layout-wrapper div.layout>section{margin:0;padding:1rem}div.layout-wrapper div.layout>section>div.content{max-width:66ch;min-width:340px}div.layout-wrapper div.layout>section>div.content.wide{max-width:100%;margin:auto}.theme-wrapper.dark header{background-color:#1a1d21}.theme-wrapper.dark div.layout-wrapper{background:#f8f9fa;background:linear-gradient(90deg, #1a1d21 0%, #1a1d21 25%, #212529 26%, #212529 100%)}.theme-wrapper.dark div.layout-wrapper div.layout{background-color:#212529}.theme-wrapper.dark div.layout-wrapper div.layout>aside{background-color:#1a1d21;border-right:2px solid #343a40}header a svg{color:#ced4da}header a:first-of-type svg{color:#f8f9fa}header a:hover svg{color:#b197fc}header a span,header button span{color:#ced4da}header a span svg,header button span svg{color:#dee2e6}header a:hover span,header button:hover span{color:#f8f9fa}header a:hover span svg,header button:hover span svg{color:#b197fc}header a,header button{padding:0 1vw !important}@media (min-width: 1200px){div.layout>section{width:63%}}@media (max-width: 1199px) and (min-width: 960px){div.layout>aside{width:298px}div.layout>section{width:calc(100% - 300px - 4rem);max-width:none;margin:0 1rem 0 3rem}}@media (max-width: 959px){div.layout>aside{width:218px}div.layout>section{width:calc(100% - 220px - 4rem);max-width:none;margin:0;padding:0 2rem}div.layout>section div.content{min-width:inherit}}@media (max-width: 599px){div.layout>aside{display:none}div.layout>section{width:calc(100%);margin:0 auto;padding:0 1.5rem;max-width:none}}div.gatsby-highlight{margin-bottom:1rem}@media (max-width: 599px){#mobile-menu{position:fixed;top:0;left:0;width:100%;height:100vh;padding:0 0 1rem;max-width:600px;z-index:-10;transition:opacity 0.25s ease 0s;opacity:0;overflow:scroll}#mobile-menu>ul,#mobile-menu>div{transform:translate(0px, 10px);transition:transform 0.25s ease 0s}.theme-wrapper.show-menu #mobile-menu{opacity:1;z-index:10}.theme-wrapper.show-menu #mobile-menu>div{transform:translate(0px, 0px)}}.theme-wrapper.light div.draft-ui-menu,.theme-wrapper.light div.menu{background:#f1f3f5}.theme-wrapper.dark div.draft-ui-menu,.theme-wrapper.dark div.menu{background:#343a40}.theme-wrapper.show-menu div.menu{opacity:1;z-index:10}.theme-wrapper.show-menu div.menu>div{transform:translate(0px, 0px)}div.spaced-buttons>button{margin:0 0.5rem 0.5rem 0}div.spaced>*{margin:0 0.5rem 0.5rem 0}ul#pre-main-menu{margin:0;padding:0}.boldish{font-weight:500}.freesewing.draft{padding:1rem}li.action{clear:both}li.action span.MuiSwitch-root{float:right}.theme-wrapper.light ul#draft-config li.action.toggle.off,.theme-wrapper.dark ul#draft-config li.action.toggle.off{color:#868e96}.theme-wrapper.light ul#draft-config li.action.toggle.off>span svg,.theme-wrapper.dark ul#draft-config li.action.toggle.off>span svg{color:#868e96}footer{background-color:#1a1d21;color:#adb5bd;padding:3rem 0 6rem}footer a{color:#dee2e6 !important;font-weight:400}footer a:hover{color:#d0bfff !important}footer div.cols{display:flex;flex-direction:row;justify-content:space-between;max-width:1600px;margin:auto;padding:0 1.5rem}footer div.cols>div{min-width:150px;max-width:calc(20% - 4rem);padding:0 2rem 0 0;width:100%}footer ul{text-align:left;font-size:1.1rem;margin:0;padding:0;width:100%}footer ul li:first-of-type{padding:0.35rem 0.75rem}footer ul li{display:block}footer ul li a:hover{text-decoration:none !important}footer ul li.heading{font-weight:bold;border-bottom:3px solid #adb5bd;margin-bottom:0.5rem}@media (min-width: 1200px){footer div.cols>div:last-of-type{min-width:350px}}@media (min-width: 600px) and (max-width: 959px){footer div.cols{flex-wrap:wrap}footer div.cols>div{width:calc(30% - 4rem);padding:0 1rem}}@media (max-width: 599px){footer div.cols{display:block}footer div.cols>div{margin:2rem auto 0;max-width:calc(100% - 4rem)}footer div.cols>div:first-of-type{margin-top:0}} diff --git a/designs/unice/example/public/manifest.json b/designs/unice/example/public/manifest.json new file mode 100644 index 00000000000..578f27ed307 --- /dev/null +++ b/designs/unice/example/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "unice", + "name": "unice", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/designs/unice/example/src/App.js b/designs/unice/example/src/App.js new file mode 100644 index 00000000000..7bb0f0e7112 --- /dev/null +++ b/designs/unice/example/src/App.js @@ -0,0 +1,45 @@ +import React from 'react' +import freesewing from '@freesewing/core' +import Workbench from '@freesewing/components/Workbench' +import '@freesewing/css-theme' +import Pattern from './pattern/src/index.js' +/* + * The following symlink is required to make this import work: + * `root_folder/example/src/pattern => `../../` + * + * Without it, we can't import the pattern as a local file + * since create-react-app does not allow imports outside ./src + * If it's imported as a dependency, webpack will cache the + * build and there will be no hot-reloading of changes + */ + +const App = (props) => { + // You can use this to add translations + /* + let translations = { + JSON: 'JSON', + someOtherString: 'Some other string that needs translation' + } + */ + + // Adds support for loading an external pattern configuration + let recreate = false + if (window) recreate = window.location.pathname.substr(1).split('/') + if (recreate.length === 3 && recreate[0] === 'recreate') { + recreate = { from: recreate[1], id: recreate[2] } + } else { + recreate = false + } + + return ( + + ) +} + +export default App diff --git a/designs/unice/example/src/index.js b/designs/unice/example/src/index.js new file mode 100644 index 00000000000..24aefad45a1 --- /dev/null +++ b/designs/unice/example/src/index.js @@ -0,0 +1,12 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import App from './App' +import * as serviceWorker from './serviceWorker' +import './layout.css' + +ReactDOM.render(, document.getElementById('root')) + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: http://bit.ly/CRA-PWA +serviceWorker.unregister() diff --git a/designs/unice/example/src/layout.css b/designs/unice/example/src/layout.css new file mode 100644 index 00000000000..a4963e16e55 --- /dev/null +++ b/designs/unice/example/src/layout.css @@ -0,0 +1,273 @@ +* { + box-sizing: border-box; +} +.MuiToolbar-root { + overflow-y: auto; +} +div.layout-wrapper { + width: 100%; + margin: 0; + padding: 0; + background: #f8f9fa; + background: linear-gradient(90deg, #f1f3f5 0%, #f1f3f5 25%, #f8f9fa 26%, #f8f9fa 100%); +} +div.layout-wrapper div.layout { + display: flex; + max-width: 1600px; + margin: auto; + padding: 0; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + background-color: #f8f9fa; + min-height: calc(100vh - 64px); +} +div.layout-wrapper div.layout > aside { + width: 33%; + background: #f1f3f5; + border-right: 2px solid #dee2e6; +} +div.layout-wrapper div.layout > section { + margin: 0; + padding: 1rem; +} +div.layout-wrapper div.layout > section > div.content { + max-width: 66ch; + min-width: 340px; +} +div.layout-wrapper div.layout > section > div.content.wide { + max-width: 100%; + margin: auto; +} + +.theme-wrapper.dark header { + background-color: #1a1d21; +} + +.theme-wrapper.dark div.layout-wrapper { + background: #f8f9fa; + background: linear-gradient(90deg, #1a1d21 0%, #1a1d21 25%, #212529 26%, #212529 100%); +} +.theme-wrapper.dark div.layout-wrapper div.layout { + background-color: #212529; +} +.theme-wrapper.dark div.layout-wrapper div.layout > aside { + background-color: #1a1d21; + border-right: 2px solid #343a40; +} + +/* monitor */ +@media (min-width: 1200px) { + div.layout > section { + width: 63%; + } +} + +/* slate */ +@media (max-width: 1199px) and (min-width: 960px) { + div.layout > aside { + width: 298px; + } + div.layout > section { + width: calc(100% - 300px - 4rem); + max-width: none; + margin: 0 1rem 0 3rem; + } +} + +/* tablet */ +@media (max-width: 959px) { + div.layout > aside { + width: 218px; + } + div.layout > section { + width: calc(100% - 220px - 4rem); + max-width: none; + margin: 0; + padding: 0 2rem; + } + div.layout > section div.content { + min-width: inherit; + } +} + +/* mobile */ +@media (max-width: 599px) { + div.layout > aside { + display: none; + } + div.layout > section { + width: calc(100%); + margin: 0 auto; + padding: 0 1.5rem; + max-width: none; + } +} + +div.gatsby-highlight { + margin-bottom: 1rem; +} + +@media (max-width: 599px) { + #mobile-menu { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; + padding: 0 0 1rem; + max-width: 600px; + z-index: -10; + transition: opacity 0.25s ease 0s; + opacity: 0; + overflow: scroll; + } + #mobile-menu > ul, + #mobile-menu > div { + transform: translate(0px, 10px); + transition: transform 0.25s ease 0s; + } + .theme-wrapper.show-menu #mobile-menu { + opacity: 1; + z-index: 10; + } + .theme-wrapper.show-menu #mobile-menu > div { + transform: translate(0px, 0px); + } +} + +.theme-wrapper.light div.draft-ui-menu, +.theme-wrapper.light div.menu { + background: #f1f3f5; +} + +.theme-wrapper.dark div.draft-ui-menu, +.theme-wrapper.dark div.menu { + background: #343a40; +} + +.theme-wrapper.show-menu div.menu { + opacity: 1; + z-index: 10; +} +.theme-wrapper.show-menu div.menu > div { + transform: translate(0px, 0px); +} + +div.spaced-buttons > button { + margin: 0 0.5rem 0.5rem 0; +} + +div.spaced > * { + margin: 0 0.5rem 0.5rem 0; +} + +ul#pre-main-menu { + margin: 0; + padding: 0; +} + +.boldish { + font-weight: 500; +} + +.freesewing.draft { + padding: 1rem; +} + +li.action { + clear: both; +} + +li.action span.MuiSwitch-root { + float: right; +} + +.theme-wrapper.light ul#draft-config li.action.toggle.off, +.theme-wrapper.dark ul#draft-config li.action.toggle.off { + color: #868e96; +} +.theme-wrapper.light ul#draft-config li.action.toggle.off > span svg, +.theme-wrapper.dark ul#draft-config li.action.toggle.off > span svg { + color: #868e96; +} + +footer { + background-color: #1a1d21; + color: #adb5bd; + padding: 3rem 0 6rem; +} +footer a { + color: #dee2e6 !important; + font-weight: 400; +} +footer a:hover { + color: #d0bfff !important; +} +footer div.cols { + display: flex; + flex-direction: row; + justify-content: space-between; + max-width: 1600px; + margin: auto; + padding: 0 1.5rem; +} +footer div.cols > div { + min-width: 150px; + max-width: calc(20% - 4rem); + padding: 0 2rem 0 0; + width: 100%; +} +footer ul { + text-align: left; + font-size: 1.1rem; + margin: 0; + padding: 0; + width: 100%; +} +footer ul li:first-of-type { + padding: 0.35rem 0.75rem; +} +footer ul li { + display: block; +} +footer ul li a:hover { + text-decoration: none !important; +} +footer ul li.heading { + font-weight: bold; + border-bottom: 3px solid #adb5bd; + margin-bottom: 0.5rem; +} + +/* XL screens */ +@media (min-width: 1200px) { + footer div.cols > div:last-of-type { + min-width: 350px; + } +} + +/* SM screens */ +@media (min-width: 600px) and (max-width: 959px) { + footer div.cols { + flex-wrap: wrap; + } + footer div.cols > div { + width: calc(30% - 4rem); + padding: 0 1rem; + } +} + +/* XS screens */ +@media (max-width: 599px) { + footer div.cols { + display: block; + } + footer div.cols > div { + margin: 2rem auto 0; + max-width: calc(100% - 4rem); + } + footer div.cols > div:first-of-type { + margin-top: 0; + } +} diff --git a/designs/unice/example/src/pattern b/designs/unice/example/src/pattern new file mode 100644 index 00000000000..6581736d623 --- /dev/null +++ b/designs/unice/example/src/pattern @@ -0,0 +1 @@ +../../ \ No newline at end of file diff --git a/designs/unice/example/src/serviceWorker.js b/designs/unice/example/src/serviceWorker.js new file mode 100644 index 00000000000..4fe923e7795 --- /dev/null +++ b/designs/unice/example/src/serviceWorker.js @@ -0,0 +1,123 @@ +// In production, we register a service worker to serve assets from local cache. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on the "N+1" visit to a page, since previously +// cached resources are updated in the background. + +// To learn more about the benefits of this model, read https://goo.gl/KwvDNy. +// This link also includes instructions on opting out of this behavior. + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) +) + +export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location) + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config) + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://goo.gl/SC7cgQ' + ) + }) + } else { + // Is not local host. Just register service worker + registerValidSW(swUrl, config) + } + }) + } +} + +function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then((registration) => { + registration.onupdatefound = () => { + const installingWorker = registration.installing + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the old content will have been purged and + // the fresh content will have been added to the cache. + // It's the perfect time to display a "New content is + // available; please refresh." message in your web app. + console.log('New content is available; please refresh.') + + // Execute callback + if (config.onUpdate) { + config.onUpdate(registration) + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.') + + // Execute callback + if (config.onSuccess) { + config.onSuccess(registration) + } + } + } + } + } + }) + .catch((error) => { + console.error('Error during service worker registration:', error) + }) +} + +function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl) + .then((response) => { + // Ensure service worker exists, and that we really are getting a JS file. + if ( + response.status === 404 || + response.headers.get('content-type').indexOf('javascript') === -1 + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then((registration) => { + registration.unregister().then(() => { + window.location.reload() + }) + }) + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config) + } + }) + .catch(() => { + console.log('No internet connection found. App is running in offline mode.') + }) +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then((registration) => { + registration.unregister() + }) + } +} diff --git a/designs/unice/package.json b/designs/unice/package.json new file mode 100644 index 00000000000..4c3f21efd5f --- /dev/null +++ b/designs/unice/package.json @@ -0,0 +1,67 @@ +{ + "name": "@freesewing/unice", + "version": "3.0.0-alpha.0", + "description": "A FreeSewing pattern for a basic, highly-customizable underwear pattern", + "author": "Anna Puk (https://github.com/anna-puk)", + "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": { + ".": "./dist/index.mjs" + }, + "scripts": { + "build": "node build.mjs", + "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", + "prettier": "npx prettier --write 'src/*.mjs' 'tests/*.mjs'", + "testci": "npx mocha tests/*.test.mjs --reporter ../../tests/reporters/terse.js", + "cibuild_step5": "node build.mjs" + }, + "peerDependencies": { + "@freesewing/core": "^3.0.0-alpha.0", + "@freesewing/plugin-bundle": "^3.0.0-alpha.0", + "@freesewing/config-helpers": "^3.0.0-alpha.0" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "^10.0.0", + "chai": "^4.2.0" + }, + "files": [ + "dist/*", + "README.md" + ], + "publishConfig": { + "access": "public", + "tag": "next" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8" + } +} diff --git a/designs/unice/src/back.mjs b/designs/unice/src/back.mjs new file mode 100644 index 00000000000..f2da67d4093 --- /dev/null +++ b/designs/unice/src/back.mjs @@ -0,0 +1,42 @@ +import { pctBasedOn } from '@freesewing/core' +import {back as ursulaBack } from '@freesewing/ursula' + +export const back = { + name: 'unice.back', + measurements: ['waist', 'seat', 'waistToSeat', 'waistToUpperLeg','hips','waistToHips'], + optionalMeasurements: ['crossSeam','crossSeamFront'], + options: { + gussetShift: 0.015, // fraction of seat circumference - could be an advanced option? + gussetWidth: { pct: 7.2, min: 2, max: 12, menu: 'fit' }, // Gusset width in relation to waist-to-upperleg + gussetLength: { pct: 12.7, min: 10, max: 16, menu: 'fit' }, // Gusset length in relation to seat + fabricStretch: { pct: 15, min: 0, max: 100, menu: 'fit' }, // used in Ursula + fabricStretchX: { pct: 15, min: 0, max: 100, menu: 'fit' }, // horizontal stretch (range set wide for beta testing) + fabricStretchY: {pct: 0, min: 0, max: 100, menu: 'fit' }, // vertical stretch (range set wide for beta testing) + rise: { pct: 60, min: 30, max: 100, menu: 'style' }, // extending rise beyond 100% would require adapting paths.sideLeft! + legOpening: { pct: 45, min: 5, max: 85, menu: 'style' }, + frontDip: { pct: 5.0, min: -5, max: 15, menu: 'style' }, + taperToGusset: { pct: 70, min: 5, max: 100, menu: 'style' }, + // booleans + useCrossSeam: { bool: true, menu: 'fit' }, + adjustStretch: {bool: true, menu: 'fit' }, // to not stretch fabric to the limits + }, + draft: ({ + utils, + store, + sa, + Point, + points, + Path, + paths, + Snippet, + snippets, + options, + measurements, + complete, + paperless, + macro, + part, + }) => { + return part + }, +} diff --git a/designs/unice/src/front.mjs b/designs/unice/src/front.mjs new file mode 100644 index 00000000000..c9a160ac812 --- /dev/null +++ b/designs/unice/src/front.mjs @@ -0,0 +1,309 @@ +import { pctBasedOn } from '@freesewing/core' + +export const front = { + name: 'unice.front', + measurements: ['waist', 'seat', 'waistToSeat', 'waistToUpperLeg','hips','waistToHips'], + optionalMeasurements: ['crossSeam','crossSeamFront'], + options: { + gussetShift: 0.015, // fraction of seat circumference - could be an advanced option? + gussetWidth: { pct: 7.2, min: 2, max: 12, menu: 'fit' }, // Gusset width in relation to waist-to-upperleg + gussetLength: { pct: 12.7, min: 10, max: 16, menu: 'fit' }, // Gusset length in relation to seat + fabricStretchX: { pct: 15, min: 0, max: 100, menu: 'fit' }, // horizontal stretch (range set wide for beta testing) + fabricStretchY: {pct: 0, min: 0, max: 100, menu: 'fit' }, // vertical stretch (range set wide for beta testing) + rise: { pct: 60, min: 30, max: 100, menu: 'style' }, // extending rise beyond 100% would require adapting paths.sideLeft! + legOpening: { pct: 45, min: 5, max: 85, menu: 'style' }, + frontDip: { pct: 5.0, min: -5, max: 15, menu: 'style' }, + taperToGusset: { pct: 70, min: 5, max: 100, menu: 'style' }, + // booleans + useCrossSeam: { bool: true, menu: 'fit' }, + adjustStretch: {bool: true, menu: 'fit' }, // to not stretch fabric to the limits + }, + draft: ({ + utils, + store, + sa, + Point, + points, + Path, + paths, + Snippet, + snippets, + options, + measurements, + complete, + paperless, + macro, + part, + }) => { + // Stretch utility method + + // Use stretch inputs to calculate four different scale factors: horizontal/vertical and 'regular'/'reduced', depending on direction of the tension + // xScale: for parts that go across the body (= stretched horizontally) + // xScaleReduced: parts that are not under (horizontal) tension, e.g. the gusset + // yScale: for parts which are stretched vertically but not horizontally (anything below leg opening) + // yScaleReduced: parts which are already under horizontal stretch, which limits vertical stretch + + if (options.adjustStretch) { // roughly 15% of stretch is reserved for comfort + // horizontal: first, 'regular' stretch (for parts that go across the body) + if (options.fabricStretchX < 0.30) { + // subtract 15, but never go below 0 + store.set('xScale', utils.stretchToScale(Math.max(0 , options.fabricStretchX - 0.15))) + } else { + store.set('xScale', utils.stretchToScale(options.fabricStretchX / 2)) + // rough approximation of rule of thumb quoted in Sanne's July 29, 2021 showcase + } + // use half of whatever the regular stretch is (no util available, convert from stretch to fraction manually + store.set('xScaleReduced',(1 + store.get('xScale'))/2) + + // vertical: + if (options.fabricStretchY < 0.30) { + // subtract 15, but never go below 0 + store.set('yScale', utils.stretchToScale(Math.max(0 , options.fabricStretchY - 0.15))) + } else { + store.set('yScale', utils.stretchToScale(options.fabricStretchY / 2)) + // rough approximation of rule of thumb quoted in Sanne's July 29, 2021 showcase + } + // reduced vertical stretch calculated below, same as for non-adjusted case + } else { + // in order: regular, then reduced horizontal stretch, followed by regular vertical stretch + store.set('xScale', utils.stretchToScale(options.fabricStretchX)) + store.set('xScaleReduced', utils.stretchToScale(options.fabricStretchX / 2)) + store.set('yScale', utils.stretchToScale(options.fabricStretchY)) + } + if (options.fabricStretchY < 0.20) { + store.set('yScaleReduced',1) + } else { + // reduced yScale gradually increases from equivalent of stretch 0 to 5%, then cuts off (uses third-order polynomial) + // function to approximate Sanne's guidelines given in Discord (roughly 2.5% for stretch 30-40%, 5% above that) + store.set('yScaleReduced', utils.stretchToScale(Math.min( 0.05, 6.25 * Math.pow(options.fabricStretchY - 0.20, 3)))) + } + + // // temporarily overrule yScale and yScaleReduced + // store.set('yScale',1) + // store.set('yScaleReduced',1) + + + // // Part definition starts here + + // determine height of front part: use cross seam (and cross seam front) if selected and available + // NOTE: neither crossSeam not frontHeight are adjusted for (vertical) stretch + if (options.useCrossSeam && measurements.crossSeam) { + store.set('crossSeam',measurements.crossSeam) + } else { // use original approximation: front and back are roughly waistToUpperLeg high, plus gusset length + store.set('crossSeam',measurements.waistToUpperLeg * (1 + options.backToFrontLength) + options.gussetLength * measurements.seat) + } + // optionally use crossSeamFront to determine relative length of front and back + // this does not account for vertical stretch yet + if (options.useCrossSeam && measurements.crossSeamFront) { // subtract half the gusset length from cross seam front, and an additional 3.5% of the seat circumference to move the gusset upward (to match commercial panties) + store.set('frontHeight',measurements.crossSeamFront - measurements.seat*(0.5*options.gussetLength + options.gussetShift)) + } else { // subtract gusset length, divide by roughly 2 + store.set('frontHeight',(store.get('crossSeam') - options.gussetLength * measurements.seat)/(1 + options.backToFrontLength)) + } + + + // Create points + + // side seam is on a line from upper leg to seat to hips (optional?) to waist + points.frontWaistMid = new Point(measurements.seat / 4, 0) + points.frontWaistLeft = new Point( + measurements.seat / 4 - (measurements.waist / 4) * store.get('xScale'), + 0 + ) + points.frontSeatLeft = new Point( + measurements.seat / 4 - (measurements.seat / 4) * store.get('xScale'), + measurements.waistToSeat * store.get('yScaleReduced') + ) + points.frontUpperLegLeft = new Point( + measurements.seat / 4 - (measurements.seat / 4) * store.get('xScale'), // assume same circ. as seat + measurements.waistToUpperLeg * store.get('yScaleReduced') + ) + points.frontHipLeft = new Point( + measurements.seat / 4 - (measurements.hips / 4) * store.get('xScale'), + measurements.waistToHips * store.get('yScaleReduced') + ) + + // use these points to define an invisible path + paths.sideLeft = new Path() + .move(points.frontUpperLegLeft) + .line(points.frontSeatLeft) + .line(points.frontHipLeft) + .line(points.frontWaistLeft) + .setRender(false) // only show when debugging + + /* Waist band is somewhere on the sideLeft path */ + points.frontWaistBandLeft = paths.sideLeft.shiftFractionAlong(options.rise) + points.frontWaistBandRight = points.frontWaistBandLeft.flipX(points.frontWaistMid) + points.frontWaistBandMid = points.frontWaistBandLeft + .shiftFractionTowards(points.frontWaistBandRight, 0.5) + .shift(270, measurements.waistToUpperLeg * options.frontDip) /* Waist band dip */ + + /* Leg opening is also on the sideLeft path, and cannot be higher than rise */ + /* Minimum side seam length is defined as 3.5% of the sideLeft path (which is at least waistToUpperLeg long) */ + store.set('adjustedLegOpening',Math.min(options.legOpening,options.rise - 0.035)) // TODO: account for rise having a different domain + + points.frontLegOpeningLeft = paths.sideLeft.shiftFractionAlong(store.get('adjustedLegOpening')) + points.frontLegOpeningRight = points.frontLegOpeningLeft.flipX(points.frontWaistMid) // Waist band low point + + // calculate the actual front height, using yScale above and yScaleReduced below leg opening + store.set('frontHeightAbove',points.frontWaistLeft.dy(points.frontLegOpeningLeft)) + + var frontHeightBelow + frontHeightBelow = store.get('yScale')*(store.get('frontHeight') - store.get('frontHeightAbove')/store.get('yScaleReduced')) + + var frontHeightReduced + frontHeightReduced = frontHeightBelow + store.get('frontHeightAbove') + + // gusset width uses modified xScale (barely stretches) and depends on waistToUpperLeg - least sensitive to girth + points.frontGussetLeft = new Point( + measurements.seat / 4 - (measurements.waistToSeat * options.gussetWidth * store.get('xScaleReduced')) * 2.2, + frontHeightReduced + ) + points.frontGussetMid = new Point(measurements.seat / 4, frontHeightReduced) + + /* Flip points to right side */ + points.frontGussetRight = points.frontGussetLeft.flipX(points.frontWaistMid) + points.frontHipRight = points.frontSeatLeft.flipX(points.frontWaistMid) + points.frontWaistRight = points.frontWaistLeft.flipX(points.frontWaistMid) + + /* Middle point for label */ + points.frontMidMid = points.frontLegOpeningLeft.shiftFractionTowards( + points.frontLegOpeningRight, + 0.5 + ) + + // Create control points + + /* Control points for leg opening curves */ + points.frontLegOpeningLeftCp1 = points.frontLegOpeningLeft.shift( + 180, + points.frontGussetLeft.dy(points.frontLegOpeningLeft) / 3 + ) + + /* Control point above gusset moves higher as taperToGusset (= front exposure) increases, but is limited by both the leg opening (allow minimal arching only) and the rise (leg opening must not intersect the waist band) */ + points.frontGussetLeftCp1 = points.frontGussetLeft + .shift(270, Math.max(Math.max(points.frontGussetLeft.dy(points.frontWaistMid) * options.taperToGusset / 2,points.frontGussetLeft.dy(points.frontLegOpeningLeft) * 2),points.frontGussetLeft.dy(points.frontWaistBandMid))) + + /* Control point for waistband dip */ + points.frontWaistBandLeftCp1 = points.frontWaistBandMid.shift(0,points.frontWaistBandMid.dx(points.frontWaistBandLeft) / 3 ) + + + /* Flip control points to right side */ + points.frontGussetRightCp1 = points.frontGussetLeftCp1.flipX(points.frontWaistMid) + points.frontLegOpeningRightCp1 = points.frontLegOpeningLeftCp1.flipX(points.frontWaistMid) + points.frontWaistBandRightCp1 = points.frontWaistBandLeftCp1.flipX(points.frontWaistMid) + + // Draw paths + + paths.seam = new Path() + .move(points.frontWaistBandMid) + .curve(points.frontWaistBandLeftCp1, points.frontWaistBandLeft, points.frontWaistBandLeft) // Waist band dip + .line(points.frontLegOpeningLeft) + .curve(points.frontLegOpeningLeftCp1, points.frontGussetLeftCp1, points.frontGussetLeft) + .line(points.frontGussetMid) + .line(points.frontGussetRight) + .curve(points.frontGussetRightCp1, points.frontLegOpeningRightCp1, points.frontLegOpeningRight) + .line(points.frontWaistBandRight) + .curve(points.frontWaistBandRight, points.frontWaistBandRightCp1, points.frontWaistBandMid) // Waist band dip + .close() + .attr('class', 'fabric') + + // Store points for use in other parts + + /* Store side seam points for use in back */ + + store.set('sideSeamWaist', points.frontWaistBandLeft) + store.set('sideSeamHip', points.frontLegOpeningLeft) + + /* Store gusset points for use in gusset */ + + store.set('frontGussetLeft', points.frontGussetLeft) + store.set('frontGussetRight', points.frontGussetRight) + store.set('frontGussetMid', points.frontGussetMid) + + /* Store lengths for use in elastic */ + + paths.frontLegOpening = new Path() + .move(points.frontGussetRight) + .curve( + points.frontGussetRightCp1, + points.frontLegOpeningRightCp1, + points.frontLegOpeningRight + ) + .setRender(false) + store.set('frontLegOpeningLength',paths.frontLegOpening.length()) + + paths.frontWaistBand = new Path() + .move(points.frontWaistBandRight) + .curve( + points.frontWaistBandRightCp1, + points.frontWaistBandLeftCp1, + points.frontWaistBandLeft + ) + .setRender(false) + store.set('frontWaistBandLength',paths.frontWaistBand.length()) + + // Complete? + if (complete) { + if (sa) { + paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa') + } + } + + macro('title', { + at: points.frontMidMid, + nr: 1, + title: 'front', + }) + + macro('grainline', { + from: points.frontGussetMid, + to: points.frontGussetMid.shiftFractionTowards(points.frontWaistBandMid, 0.5), + }) + + // Paperless? + if (paperless) { + macro('hd', { + from: points.frontWaistBandRight, + to: points.frontWaistBandLeft, + y: points.frontWaistBandRight.y + sa - 15, + }) + macro('hd', { + from: points.frontLegOpeningRight, + to: points.frontLegOpeningLeft, + y: points.frontLegOpeningRight.y + sa - 15, + }) + macro('hd', { + from: points.frontGussetLeft, + to: points.frontGussetRight, + y: points.frontGussetLeft.y + sa + 15, + }) + macro('vd', { + from: points.frontWaistBandMid, + to: points.frontGussetMid, + x: points.frontWaistBandMid.x + sa + 15, + }) + macro('ld', { + from: points.frontWaistBandLeft, + to: points.frontLegOpeningLeft, + d: points.frontWaistBandLeft.y + sa - 15, + }) + macro('pd', { + path: new Path() + .move(points.frontGussetRight) + .curve( + points.frontGussetRightCp1, + points.frontLegOpeningRightCp1, + points.frontLegOpeningRight + ), + d: 15, + }) + /* macro('vd', { + from: points.frontWaistBandLeft, + to: points.frontWaistBandMid, + x: points.frontWaistBandMid.x + sa + 15, + }) */ + } + + return part + }, +} diff --git a/designs/unice/src/gusset.mjs b/designs/unice/src/gusset.mjs new file mode 100644 index 00000000000..39b86acb13d --- /dev/null +++ b/designs/unice/src/gusset.mjs @@ -0,0 +1,4 @@ +const method = part => part + +export default method + diff --git a/designs/unice/src/index.mjs b/designs/unice/src/index.mjs new file mode 100644 index 00000000000..b8c55238e26 --- /dev/null +++ b/designs/unice/src/index.mjs @@ -0,0 +1,14 @@ +import { Design } from '@freesewing/core' +import { front } from './front.mjs' +// import { back } from './back.mjs' +// import { gusset } from './gusset.mjs' +import { data } from '../data.mjs' + +// Setup our new design +const Unice = new Design({ + data, + parts: [front], // parts: [back, front], +}) + +// Named exports +export {front, Unice} // export { back, front, gusset, Unice } \ No newline at end of file diff --git a/designs/unice/tests/shared.test.mjs b/designs/unice/tests/shared.test.mjs new file mode 100644 index 00000000000..13c82f4ee71 --- /dev/null +++ b/designs/unice/tests/shared.test.mjs @@ -0,0 +1,16 @@ +// This file is auto-generated | Any changes you make will be overwritten. +import { Unice } from './dist/index.mjs' + +// Shared tests +import { testPatternConfig } from '../../../tests/designs/config.mjs' +import { testPatternDrafting } from '../../../tests/designs/drafting.mjs' +import { testPatternSampling } from '../../../tests/designs/sampling.mjs' + +// Test config +testPatternConfig(Unice) + +// Test drafting - Change the second parameter to `true` to log errors +testPatternDrafting(Unice, false) + +// Test sampling - Change the second parameter to `true` to log errors +testPatternSampling(Unice, false)