first commit
This commit is contained in:
parent
84899dea1a
commit
5827b79afa
39 changed files with 88385 additions and 0 deletions
9
packages/yuri/.babelrc
Normal file
9
packages/yuri/.babelrc
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"presets": [
|
||||
["@babel/preset-env", {
|
||||
"modules": false
|
||||
}],
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": ["@babel/plugin-proposal-class-properties"]
|
||||
}
|
9
packages/yuri/.editorconfig
Normal file
9
packages/yuri/.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
23
packages/yuri/.eslintrc
Normal file
23
packages/yuri/.eslintrc
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"parser": "babel-eslint",
|
||||
"extends": [
|
||||
"standard",
|
||||
"standard-react"
|
||||
],
|
||||
"env": {
|
||||
"es6": true
|
||||
},
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
// don't force es6 functions to include space before paren
|
||||
"space-before-function-paren": 0,
|
||||
|
||||
// allow specifying true explicitly for boolean props
|
||||
"react/jsx-boolean-value": 0
|
||||
}
|
||||
}
|
2
packages/yuri/.gitignore
vendored
Normal file
2
packages/yuri/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
dist
|
||||
node_modules
|
2
packages/yuri/.npmignore
Normal file
2
packages/yuri/.npmignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules/
|
||||
dist/
|
4
packages/yuri/.travis.yml
Normal file
4
packages/yuri/.travis.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 9
|
||||
- 8
|
21
packages/yuri/LICENSE
Normal file
21
packages/yuri/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Biou
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
31
packages/yuri/README.md
Normal file
31
packages/yuri/README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# yuri
|
||||
|
||||
>
|
||||
|
||||
[](https://www.npmjs.com/package/yuri) [](https://standardjs.com)
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install --save yuri
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
import React, { Component } from 'react'
|
||||
|
||||
import MyComponent from 'yuri'
|
||||
|
||||
class Example extends Component {
|
||||
render () {
|
||||
return (
|
||||
<MyComponent />
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
© [biou](https://github.com/biou)
|
145
packages/yuri/config/index.js
Normal file
145
packages/yuri/config/index.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
import { version } from '../package.json'
|
||||
|
||||
export default {
|
||||
name: 'yuri',
|
||||
version: version,
|
||||
design: 'Hellgy',
|
||||
code: 'Biou',
|
||||
department: 'tops',
|
||||
type: 'pattern',
|
||||
difficulty: 3,
|
||||
optionGroups: {
|
||||
fit: [
|
||||
'bicepsEase',
|
||||
'chestEase',
|
||||
'cuffEase',
|
||||
'collarEase',
|
||||
'shoulderEase',
|
||||
'hipsEase',
|
||||
'ribbingStretch',
|
||||
],
|
||||
style: [
|
||||
'lengthBonus',
|
||||
'sleeveLengthBonus',
|
||||
'ribbing',
|
||||
'ribbingHeight',
|
||||
's3Collar',
|
||||
's3Armhole',
|
||||
],
|
||||
advanced: [
|
||||
'acrossBackFactor',
|
||||
'armholeDepthFactor',
|
||||
'backNeckCutout',
|
||||
'frontArmholeDeeper',
|
||||
'sleeveWidthGuarantee',
|
||||
{
|
||||
sleevecap: [
|
||||
'sleevecapEase',
|
||||
'sleevecapTopFactorX',
|
||||
'sleevecapTopFactorY',
|
||||
'sleevecapBackFactorX',
|
||||
'sleevecapBackFactorY',
|
||||
'sleevecapFrontFactorX',
|
||||
'sleevecapFrontFactorY',
|
||||
'sleevecapQ1Offset',
|
||||
'sleevecapQ2Offset',
|
||||
'sleevecapQ3Offset',
|
||||
'sleevecapQ4Offset',
|
||||
'sleevecapQ1Spread1',
|
||||
'sleevecapQ1Spread2',
|
||||
'sleevecapQ2Spread1',
|
||||
'sleevecapQ2Spread2',
|
||||
'sleevecapQ3Spread1',
|
||||
'sleevecapQ3Spread2',
|
||||
'sleevecapQ4Spread1',
|
||||
'sleevecapQ4Spread2',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
measurements: [
|
||||
'biceps',
|
||||
'chest',
|
||||
'head',
|
||||
'hips',
|
||||
'hpsToWaistBack',
|
||||
'waistToHips',
|
||||
'neck',
|
||||
'shoulderSlope',
|
||||
'shoulderToShoulder',
|
||||
'shoulderToWrist',
|
||||
'wrist',
|
||||
'hpsToBust',
|
||||
],
|
||||
dependencies: {
|
||||
backBase: 'base',
|
||||
frontBase: 'backBase',
|
||||
sleevecap: 'frontBase',
|
||||
sleeveBase: 'sleevecap',
|
||||
back: 'backBase',
|
||||
front: 'frontBase',
|
||||
sleeve: 'sleeveBase',
|
||||
// hoodCenter: 'hoodSide',
|
||||
// hoodSide: ['front', 'back'],
|
||||
},
|
||||
inject: {
|
||||
backBase: 'base',
|
||||
frontBase: 'backBase',
|
||||
sleeveBase: 'sleevecap',
|
||||
back: 'backBase',
|
||||
front: 'frontBase',
|
||||
sleeve: 'sleeveBase',
|
||||
},
|
||||
hide: ['base', 'sleevecap', 'backBase', 'frontBase', 'sleeveBase'],
|
||||
parts: ['cuff', 'gusset', 'hoodSide', 'hoodCenter'],
|
||||
options: {
|
||||
// Constants
|
||||
brianFitSleeve: true,
|
||||
brianFitCollar: true,
|
||||
collarFactor: 4.8,
|
||||
shoulderSlopeReduction: 0,
|
||||
|
||||
// Options inherited from Brian
|
||||
acrossBackFactor: { pct: 97, min: 93, max: 100 },
|
||||
armholeDepthFactor: { pct: 65, min: 50, max: 70 },
|
||||
backNeckCutout: { pct: 5, min: 2, max: 8 },
|
||||
bicepsEase: { pct: 8, min: 0, max: 20 },
|
||||
chestEase: { pct: 8, min: -4, max: 20 },
|
||||
collarEase: { pct: 20, min: 10, max: 30 },
|
||||
cuffEase: { pct: 20, min: 10, max: 60 },
|
||||
frontArmholeDeeper: { pct: 0.5, min: 0, max: 1.5 },
|
||||
lengthBonus: { pct: 10, min: 5, max: 15 },
|
||||
shoulderEase: { pct: 0.5, min: -2, max: 6 },
|
||||
// s3 is short for Shoulder Seam Shift
|
||||
s3Collar: { pct: 0, min: -100, max: 100 },
|
||||
s3Armhole: { pct: 0, min: -100, max: 100 },
|
||||
sleeveLengthBonus: { pct: 1, min: 0, max: 10 },
|
||||
sleevecapEase: { pct: 0, min: 0, max: 10 },
|
||||
sleevecapTopFactorX: { pct: 50, min: 25, max: 75 },
|
||||
sleevecapTopFactorY: { pct: 100, min: 35, max: 165 },
|
||||
sleevecapBackFactorX: { pct: 60, min: 35, max: 65 },
|
||||
sleevecapBackFactorY: { pct: 33, min: 30, max: 65 },
|
||||
sleevecapFrontFactorX: { pct: 55, min: 35, max: 65 },
|
||||
sleevecapFrontFactorY: { pct: 33, min: 30, max: 65 },
|
||||
sleevecapQ1Offset: { pct: 3, min: 0, max: 7 },
|
||||
sleevecapQ2Offset: { pct: 5.5, min: 0, max: 7 },
|
||||
sleevecapQ3Offset: { pct: 4.5, min: 0, max: 7 },
|
||||
sleevecapQ4Offset: { pct: 1, min: 0, max: 7 },
|
||||
sleevecapQ1Spread1: { pct: 6, min: 4, max: 20 },
|
||||
sleevecapQ1Spread2: { pct: 15, min: 4, max: 20 },
|
||||
sleevecapQ2Spread1: { pct: 15, min: 4, max: 20 },
|
||||
sleevecapQ2Spread2: { pct: 10, min: 4, max: 20 },
|
||||
sleevecapQ3Spread1: { pct: 10, min: 4, max: 20 },
|
||||
sleevecapQ3Spread2: { pct: 8, min: 4, max: 20 },
|
||||
sleevecapQ4Spread1: { pct: 7, min: 4, max: 20 },
|
||||
sleevecapQ4Spread2: { pct: 7, min: 4, max: 20 },
|
||||
sleeveWidthGuarantee: { pct: 90, min: 25, max: 100 },
|
||||
|
||||
// Options specific to Yuri
|
||||
ribbing: { bool: false },
|
||||
|
||||
ribbingHeight: { pct: 10, min: 5, max: 15 },
|
||||
hipsEase: { pct: 0, min: 0, max: 10 },
|
||||
ribbingStretch: { pct: 15, min: 0, max: 30 },
|
||||
},
|
||||
}
|
10
packages/yuri/example/.babelrc
Normal file
10
packages/yuri/example/.babelrc
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"plugins": [
|
||||
["prismjs", {
|
||||
"languages": ["javascript", "css", "markup"],
|
||||
"plugins": ["line-numbers"],
|
||||
"theme": "twilight",
|
||||
"css": true
|
||||
}]
|
||||
]
|
||||
}
|
1
packages/yuri/example/.env
Normal file
1
packages/yuri/example/.env
Normal file
|
@ -0,0 +1 @@
|
|||
SKIP_PREFLIGHT_CHECK=true
|
96
packages/yuri/example/README.md
Normal file
96
packages/yuri/example/README.md
Normal file
|
@ -0,0 +1,96 @@
|
|||
<p align="center">
|
||||
<a title="Go to freesewing.org" href="https://freesewing.org/"><img src="https://freesewing.org/img/logo/black.svg" align="center" width="150px" alt="Freesewing logo"/></a>
|
||||
<br>
|
||||
<a href="https://freesewing.org/">FreeSewing v2</a>
|
||||
</p>
|
||||
<p align="center">A JavaScript library for made-to-measure sewing patterns</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://gitter.im/freesewing/freesewing"
|
||||
title="Chat with us on Gitter"
|
||||
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Chat%20with%20us-CA0547.svg?logo=gitter&logoColor=white&logoWidth=15"
|
||||
alt="Chat with us on Gitter"/>
|
||||
</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>
|
||||
|
||||
# yuri 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://yuri.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).
|
||||
|
9
packages/yuri/example/netlify.toml
Normal file
9
packages/yuri/example/netlify.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[build]
|
||||
base = "packages/yuri/example"
|
||||
publish = "build"
|
||||
command = "npm run build"
|
||||
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
40090
packages/yuri/example/package-lock.json
generated
Normal file
40090
packages/yuri/example/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
51
packages/yuri/example/package.json
Normal file
51
packages/yuri/example/package.json
Normal file
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"name": "yuri",
|
||||
"homepage": "https://yuri.freesewing.dev/",
|
||||
"version": "2.17.0",
|
||||
"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.23.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-intl": "^5.18.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"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"
|
||||
}
|
||||
}
|
BIN
packages/yuri/example/public/favicon.ico
Normal file
BIN
packages/yuri/example/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
41
packages/yuri/example/public/index.html
Normal file
41
packages/yuri/example/public/index.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<link rel="stylesheet" href="layout.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>yuri</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
1
packages/yuri/example/public/layout.css
Normal file
1
packages/yuri/example/public/layout.css
Normal file
|
@ -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}}
|
15
packages/yuri/example/public/manifest.json
Normal file
15
packages/yuri/example/public/manifest.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"short_name": "yuri",
|
||||
"name": "yuri",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
45
packages/yuri/example/src/App.js
Normal file
45
packages/yuri/example/src/App.js
Normal file
|
@ -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 (
|
||||
<Workbench
|
||||
freesewing={freesewing}
|
||||
Pattern={Pattern}
|
||||
userLanguage="en"
|
||||
recreate={recreate}
|
||||
// translations={translations}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
9
packages/yuri/example/src/App.test.js
Normal file
9
packages/yuri/example/src/App.test.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import App from './App'
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const div = document.createElement('div')
|
||||
ReactDOM.render(<App />, div)
|
||||
ReactDOM.unmountComponentAtNode(div)
|
||||
})
|
12
packages/yuri/example/src/index.js
Normal file
12
packages/yuri/example/src/index.js
Normal file
|
@ -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(<App />, 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()
|
213
packages/yuri/example/src/layout.css
Normal file
213
packages/yuri/example/src/layout.css
Normal file
|
@ -0,0 +1,213 @@
|
|||
* {
|
||||
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; } }
|
284
packages/yuri/example/src/layout.scss
Normal file
284
packages/yuri/example/src/layout.scss
Normal file
|
@ -0,0 +1,284 @@
|
|||
@import '../../../../../../node_modules/open-color/open-color.scss';
|
||||
|
||||
// Global style overrides
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.MuiToolbar-root {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
// Main page content layout
|
||||
div.layout-wrapper {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: $oc-gray-0;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
$oc-gray-1 0%,
|
||||
$oc-gray-1 25%,
|
||||
$oc-gray-0 26%,
|
||||
$oc-gray-0 100%
|
||||
);
|
||||
div.layout {
|
||||
display: flex;
|
||||
max-width: 1600px;
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
background-color: $oc-gray-0;
|
||||
min-height: calc(100vh - 64px);
|
||||
> aside {
|
||||
width: 33%;
|
||||
background: $oc-gray-1;
|
||||
border-right: 2px solid $oc-gray-3;
|
||||
}
|
||||
> section {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
> div.content {
|
||||
max-width: 66ch;
|
||||
min-width: 340px;
|
||||
}
|
||||
> div.content.wide {
|
||||
max-width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.theme-wrapper.dark {
|
||||
header {
|
||||
background-color: darken($oc-gray-9, 3);
|
||||
}
|
||||
div.layout-wrapper {
|
||||
background: $oc-gray-0;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
darken($oc-gray-9, 3) 0%,
|
||||
darken($oc-gray-9, 3) 25%,
|
||||
$oc-gray-9 26%,
|
||||
$oc-gray-9 100%
|
||||
);
|
||||
div.layout {
|
||||
background-color: $oc-gray-9;
|
||||
> aside {
|
||||
background-color: darken($oc-gray-9, 3);
|
||||
border-right: 2px solid $oc-gray-8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* monitor */
|
||||
@media (min-width: 1200px) {
|
||||
div.layout > section {
|
||||
width: 63%;
|
||||
}
|
||||
}
|
||||
/* slate */
|
||||
@media (max-width: 1199px) and (min-width: 960px) {
|
||||
div.layout {
|
||||
> aside {
|
||||
width: 298px; // 2px border
|
||||
}
|
||||
> section {
|
||||
width: calc(100% - 300px - 4rem);
|
||||
max-width: none;
|
||||
margin: 0 1rem 0 3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* tablet */
|
||||
@media (max-width: 959px) {
|
||||
div.layout {
|
||||
> aside {
|
||||
width: 218px; // 2px border
|
||||
}
|
||||
> section {
|
||||
width: calc(100% - 220px - 4rem);
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
padding: 0 2rem;
|
||||
div.content {
|
||||
min-width: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* mobile */
|
||||
@media (max-width: 599px) {
|
||||
div.layout {
|
||||
> aside {
|
||||
display: none;
|
||||
}
|
||||
> section {
|
||||
width: calc(100%);
|
||||
margin: 0 auto;
|
||||
padding: 0 1.5rem;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Candidates for theme inclusion
|
||||
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;
|
||||
> ul,
|
||||
> div {
|
||||
transform: translate(0px, 10px);
|
||||
transition: transform 0.25s ease 0s;
|
||||
}
|
||||
}
|
||||
.theme-wrapper.show-menu #mobile-menu {
|
||||
opacity: 1;
|
||||
z-index: 10;
|
||||
> div {
|
||||
transform: translate(0px, 0px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme-wrapper.light div.draft-ui-menu,
|
||||
.theme-wrapper.light div.menu {
|
||||
background: $oc-gray-1;
|
||||
}
|
||||
.theme-wrapper.dark div.draft-ui-menu,
|
||||
.theme-wrapper.dark div.menu {
|
||||
background: $oc-gray-8;
|
||||
}
|
||||
.theme-wrapper.show-menu div.menu {
|
||||
opacity: 1;
|
||||
z-index: 10;
|
||||
> 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: $oc-gray-6;
|
||||
> span svg {
|
||||
color: $oc-gray-6;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: #1a1d21;
|
||||
color: #adb5bd;
|
||||
padding: 3rem 0 6rem;
|
||||
a {
|
||||
color: #dee2e6 !important;
|
||||
font-weight: 400;
|
||||
}
|
||||
a:hover {
|
||||
color: #d0bfff !important;
|
||||
}
|
||||
div.cols {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
max-width: 1600px;
|
||||
margin: auto;
|
||||
padding: 0 1.5rem;
|
||||
> div {
|
||||
min-width: 150px;
|
||||
max-width: calc(20% - 4rem);
|
||||
padding: 0 2rem 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
ul {
|
||||
text-align: left;
|
||||
font-size: 1.1rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
li:first-of-type {
|
||||
padding: 0.35rem 0.75rem;
|
||||
}
|
||||
li {
|
||||
display: block;
|
||||
a:hover {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
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;
|
||||
> div {
|
||||
width: calc(30% - 4rem);
|
||||
padding: 0 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* XS screens */
|
||||
@media (max-width: 599px) {
|
||||
footer div.cols {
|
||||
display: block;
|
||||
> div {
|
||||
margin: 2rem auto 0;
|
||||
max-width: calc(100% - 4rem);
|
||||
}
|
||||
> div:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
1
packages/yuri/example/src/pattern
Symbolic link
1
packages/yuri/example/src/pattern
Symbolic link
|
@ -0,0 +1 @@
|
|||
/Users/biou/Projects/yuri
|
123
packages/yuri/example/src/serviceWorker.js
Normal file
123
packages/yuri/example/src/serviceWorker.js
Normal file
|
@ -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()
|
||||
})
|
||||
}
|
||||
}
|
46218
packages/yuri/package-lock.json
generated
Normal file
46218
packages/yuri/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
67
packages/yuri/package.json
Normal file
67
packages/yuri/package.json
Normal file
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"name": "@biou/yuri",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "hellgy",
|
||||
"license": "MIT",
|
||||
"repository": "github:biou/yuri",
|
||||
"bugs": {
|
||||
"url": "https://github.com/biou/yuri/issues"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.es.js",
|
||||
"jsnext:main": "dist/index.es.js",
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"start": "rollup -c -w",
|
||||
"prepare": "npm run build",
|
||||
"predeploy": "cd example && npm install && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@freesewing/core": "^2.17.1",
|
||||
"@freesewing/plugin-bundle": "^2.17.1",
|
||||
"@freesewing/brian": "^2.17.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"@freesewing/core": "latest",
|
||||
"@freesewing/plugin-bundle": "latest",
|
||||
"@freesewing/components": "latest",
|
||||
"@freesewing/css-theme": "latest",
|
||||
"@freesewing/i18n": "latest",
|
||||
"@freesewing/mui-theme": "latest",
|
||||
"@freesewing/plugin-bust": "latest",
|
||||
"@freesewing/plugin-buttons": "latest",
|
||||
"@freesewing/plugin-debug": "latest",
|
||||
"@freesewing/plugin-flip": "latest",
|
||||
"@freesewing/utils": "latest",
|
||||
"react-scripts": "^4.0.3",
|
||||
"webpack": "^5.37.0",
|
||||
"rollup": "^2.48.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"@rollup/plugin-babel": "^5.1.0",
|
||||
"@rollup/plugin-commonjs": "^14.0.0",
|
||||
"@rollup/plugin-url": "^6.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@rollup/plugin-yaml": "^3.0.0",
|
||||
"@material-ui/core": "^4.11.4",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.58",
|
||||
"axios": "0.21.1",
|
||||
"react-intl": "5.17.6",
|
||||
"prop-types": "15.7.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"eslint": "^7.27.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-config-standard-react": "^11.0.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.0"
|
||||
}
|
||||
}
|
43
packages/yuri/rollup.config.js
Normal file
43
packages/yuri/rollup.config.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import url from '@rollup/plugin-url'
|
||||
import babel from '@rollup/plugin-babel'
|
||||
import resolve from '@rollup/plugin-node-resolve'
|
||||
import commonjs from '@rollup/plugin-commonjs'
|
||||
import json from '@rollup/plugin-json'
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
import peerDepsExternal from 'rollup-plugin-peer-deps-external'
|
||||
// import postcss from 'rollup-plugin-postcss'
|
||||
import { main, module, name, version, description, author, license } from './package.json'
|
||||
|
||||
export default {
|
||||
input: 'src/index.js',
|
||||
output: [
|
||||
{
|
||||
file: main,
|
||||
format: 'cjs',
|
||||
sourcemap: true,
|
||||
exports: 'default'
|
||||
},
|
||||
{
|
||||
file: module,
|
||||
format: 'es',
|
||||
sourcemap: true,
|
||||
exports: 'default'
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
peerDepsExternal(),
|
||||
// postcss({ modules: true }),
|
||||
url({ exclude: ['**/*.svg'] }),
|
||||
babel({
|
||||
exclude: 'node_modules/**'
|
||||
}),
|
||||
resolve({ browser: true }),
|
||||
json(),
|
||||
commonjs(),
|
||||
terser({
|
||||
output: {
|
||||
preamble: `/**\n * ${name} | v${version}\n * ${description}\n * (c) ${new Date().getFullYear()} ${author}\n * @license ${license}\n */`
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
5
packages/yuri/src/.eslintrc
Normal file
5
packages/yuri/src/.eslintrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
}
|
98
packages/yuri/src/back.js
Normal file
98
packages/yuri/src/back.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
import { sharedDimensions } from './shared'
|
||||
|
||||
export default function (part) {
|
||||
const {
|
||||
store,
|
||||
macro,
|
||||
Path,
|
||||
Point,
|
||||
points,
|
||||
paths,
|
||||
complete,
|
||||
paperless,
|
||||
sa,
|
||||
options,
|
||||
measurements
|
||||
} = part.shorthand()
|
||||
|
||||
// Clear paths from Brian
|
||||
for (const i in paths) {
|
||||
if (['backArmhole', 'backCollar'].indexOf(i) === -1) delete paths[i]
|
||||
}
|
||||
|
||||
// Shorten body to take ribbing into account
|
||||
if (options.ribbing) {
|
||||
const rh = options.ribbingHeight * (measurements.hpsToWaistBack + measurements.waistToHips)
|
||||
for (const p of ['hem', 'cbHem']) points[p] = points[p].shift(90, rh)
|
||||
store.set('ribbingHeight', rh)
|
||||
}
|
||||
|
||||
// Shape side seam
|
||||
points.hips.x = (measurements.hips * (1 + options.hipsEase)) / 4
|
||||
points.hem.x = points.hips.x
|
||||
points.hemCp2 = new Point(points.hips.x, points.cbWaist.y)
|
||||
|
||||
// add some points for Yuri
|
||||
points.cbBottom = new Point(0, points.cbHem.y * 1.27)
|
||||
points.bottom = new Point(points.hem.x * 1.23, points.cbBottom.y * 0.97)
|
||||
points.bottomCp2 = new Point(points.bottom.x, points.cbWaist.y)
|
||||
// end Yuri points
|
||||
|
||||
// Store length of the neck seam
|
||||
store.set(
|
||||
'backNeckSeamLength',
|
||||
new Path().move(points.neck).curve_(points.neckCp2, points.cbNeck).length()
|
||||
)
|
||||
store.set(
|
||||
'neckCutoutBack',
|
||||
points.cbNeck.y
|
||||
)
|
||||
|
||||
console.log(points.bottom)
|
||||
// Paths
|
||||
paths.gussetBase = new Path().move(points.bottom).line(points.armhole).attr('class', 'note stroke-xxl')
|
||||
store.set('gussetLength', paths.gussetBase.length())
|
||||
paths.saBase = new Path()
|
||||
.move(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholeHollowCp1, points.armholeHollow)
|
||||
.curve(points.armholeHollowCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.join(paths.backArmhole)
|
||||
.line(points.s3CollarSplit)
|
||||
.join(paths.backCollar)
|
||||
.attr('class', 'note stroke-xxl')
|
||||
paths.hemBase = new Path().move(points.cbBottom).line(points.bottom).attr('class', 'note stroke-xxl')
|
||||
paths.gussetBase.render = false
|
||||
paths.saBase.render = false
|
||||
paths.hemBase.render = false
|
||||
|
||||
paths.seam = paths.gussetBase.join(paths.saBase)
|
||||
.clone()
|
||||
.line(points.cbBottom)
|
||||
.join(paths.hemBase)
|
||||
.close()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
// Complete?
|
||||
if (complete) {
|
||||
macro('cutonfold', {
|
||||
from: points.cbNeck,
|
||||
to: points.cbBottom,
|
||||
grainline: true
|
||||
})
|
||||
macro('scalebox', { at: new Point(points.armholePitch.x / 2, points.cbWaist.y) })
|
||||
if (sa) {
|
||||
paths.sa = paths.hemBase.offset(options.ribbing ? sa : 3 * sa).join(paths.saBase.offset(sa))
|
||||
paths.sa
|
||||
.move(paths.sa.end())
|
||||
.line(points.cbNeck)
|
||||
.move(paths.sa.start())
|
||||
.line(points.cbBottom)
|
||||
.attr('class', 'fabric sa')
|
||||
}
|
||||
}
|
||||
|
||||
// Paperless?
|
||||
if (paperless) sharedDimensions(part, 'back')
|
||||
|
||||
return part
|
||||
}
|
19
packages/yuri/src/cuff.js
Normal file
19
packages/yuri/src/cuff.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { draftRibbing } from './shared'
|
||||
|
||||
export default (part) => {
|
||||
const { complete, points, measurements, options, macro } = part.shorthand()
|
||||
if (!options.ribbing) return part
|
||||
|
||||
draftRibbing(part, measurements.wrist * (1 + options.cuffEase) * (1 - options.ribbingStretch))
|
||||
|
||||
// Complete pattern?
|
||||
if (complete) {
|
||||
macro('title', {
|
||||
at: points.title,
|
||||
nr: 7,
|
||||
title: 'cuff'
|
||||
})
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
90
packages/yuri/src/front.js
Normal file
90
packages/yuri/src/front.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { sharedDimensions } from './shared'
|
||||
|
||||
export default function (part) {
|
||||
const {
|
||||
store,
|
||||
Point,
|
||||
Path,
|
||||
points,
|
||||
paths,
|
||||
complete,
|
||||
paperless,
|
||||
sa,
|
||||
options,
|
||||
measurements,
|
||||
macro
|
||||
} = part.shorthand()
|
||||
|
||||
// Clear paths from Brian
|
||||
for (const i in paths) {
|
||||
if (['frontArmhole', 'frontCollar'].indexOf(i) === -1) delete paths[i]
|
||||
}
|
||||
|
||||
// Shorten body to take ribbing into account
|
||||
if (options.ribbing) {
|
||||
for (const p of ['hem', 'cfHem']) points[p] = points[p].shift(90, store.get('ribbingHeight'))
|
||||
}
|
||||
|
||||
// Shape side seam
|
||||
points.hips.x = (measurements.hips * (1 + options.hipsEase)) / 4
|
||||
points.hem.x = points.hips.x
|
||||
points.hemCp2 = new Point(points.hips.x, points.cfWaist.y)
|
||||
|
||||
// add some points for Yuri
|
||||
points.cfBottom = new Point(0, points.cfHem.y * 1.27)
|
||||
points.bottom = new Point(points.hem.x * 1.23, points.cfBottom.y * 0.97)
|
||||
points.bottomCp2 = new Point(points.bottom.x, points.cfWaist.y)
|
||||
points.button = new Point(points.s3CollarSplit.x - 2 / 3 * measurements.shoulderToShoulder, points.s3CollarSplit.y + measurements.hpsToBust * 1.17)
|
||||
// end Yuri points
|
||||
|
||||
// Store length of the neck seam
|
||||
store.set(
|
||||
'frontNeckSeamLength',
|
||||
new Path()
|
||||
.move(points.neck)
|
||||
.curve(points.neckCp2Front, points.cfNeckCp1, points.cfNeck)
|
||||
.length()
|
||||
)
|
||||
store.set(
|
||||
'neckCutoutFront',
|
||||
points.cfNeck.y
|
||||
)
|
||||
|
||||
// Paths
|
||||
paths.saBase = new Path()
|
||||
.move(points.bottom)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholeHollowCp1, points.armholeHollow)
|
||||
.curve(points.armholeHollowCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.join(paths.frontArmhole)
|
||||
.line(points.s3CollarSplit)
|
||||
.attr('class', 'note stroke-xxl')
|
||||
paths.buttonBase = new Path()
|
||||
.move(points.s3CollarSplit)
|
||||
.line(points.button)
|
||||
.line(points.cfBottom)
|
||||
.attr('class', 'note stroke-xxl')
|
||||
paths.hemBase = new Path().move(points.cfBottom).line(points.bottom).attr('class', 'note stroke-xxl')
|
||||
paths.saBase.render = false
|
||||
paths.hemBase.render = false
|
||||
paths.buttonBase.render = false
|
||||
|
||||
paths.seam = paths.saBase.clone().join(paths.buttonBase).join(paths.hemBase).close().attr('class', 'fabric')
|
||||
|
||||
// Complete?
|
||||
if (complete) {
|
||||
macro('grainline', {
|
||||
from: points.s3CollarSplit,
|
||||
to: new Point(points.s3CollarSplit.x, points.bottom.y)
|
||||
})
|
||||
if (sa) {
|
||||
paths.sa = paths.hemBase.offset(options.ribbing ? sa : 3 * sa).join(paths.saBase.offset(sa)).join(paths.buttonBase.offset(3 * sa))
|
||||
paths.sa = paths.sa.line(paths.sa.start()).close().attr('class', 'fabric sa')
|
||||
}
|
||||
}
|
||||
|
||||
// Paperless?
|
||||
if (paperless) sharedDimensions(part, 'front')
|
||||
|
||||
return part
|
||||
}
|
71
packages/yuri/src/gusset.js
Normal file
71
packages/yuri/src/gusset.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
export default function (part) {
|
||||
const {
|
||||
Point,
|
||||
Path,
|
||||
points,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
complete,
|
||||
sa,
|
||||
paperless,
|
||||
macro,
|
||||
store
|
||||
} = part.shorthand()
|
||||
|
||||
const w = store.get('gussetLength')
|
||||
points.top = new Point(0, 0)
|
||||
points.bottom = new Point(0, w)
|
||||
points.right = points.bottom.rotate(33.0, points.top)
|
||||
points.cp1 = new Point(0, w * 6 / 5).rotate(90, points.bottom)
|
||||
points.cp2 = new Point(points.right.x, points.right.y * 6 / 5).rotate(-60, points.right)
|
||||
points.title = new Point(0, 2 * w / 3).rotate(15, points.top)
|
||||
|
||||
paths.hat = new Path()
|
||||
.move(points.right)
|
||||
.line(points.top)
|
||||
.line(points.bottom)
|
||||
.attr('class', 'fabric')
|
||||
|
||||
paths.curve = new Path()
|
||||
.move(points.bottom)
|
||||
.curve(points.cp1, points.cp2, points.right)
|
||||
.attr('class', 'fabric')
|
||||
|
||||
paths.seam = paths.hat.join(paths.curve)
|
||||
|
||||
// Complete?
|
||||
if (complete) {
|
||||
macro('cutonfold', {
|
||||
from: new Point(points.top.x, points.top.y + 50),
|
||||
to: points.bottom,
|
||||
grainline: true
|
||||
})
|
||||
macro('title', {
|
||||
at: points.title,
|
||||
nr: 4,
|
||||
title: 'gusset'
|
||||
})
|
||||
points.logo = points.title.shift(-75, 100)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
if (sa) {
|
||||
paths.sa = paths.hat.offset(sa).join(paths.curve.offset(3 * sa)).attr('class', 'fabric sa')
|
||||
}
|
||||
}
|
||||
|
||||
// Paperless?
|
||||
if (paperless) {
|
||||
macro('hd', {
|
||||
from: points.bottomLeft,
|
||||
to: points.bottomRight,
|
||||
y: points.bottomLeft.y + sa + 15
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.bottomRight,
|
||||
to: points.topRight,
|
||||
x: points.topRight.x + sa + 15
|
||||
})
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
82
packages/yuri/src/hoodcenter.js
Normal file
82
packages/yuri/src/hoodcenter.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
export default function (part) {
|
||||
const {
|
||||
store,
|
||||
sa,
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
complete,
|
||||
paperless,
|
||||
macro,
|
||||
units
|
||||
} = part.shorthand()
|
||||
|
||||
const width = store.get('hoodCenterWidth')
|
||||
const length = complete ? width * 2.5 : store.get('hoodCenterLength')
|
||||
points.topLeft = new Point(0, 0)
|
||||
points.bottomLeft = new Point(0, width)
|
||||
points.topMidLeft = new Point(width, 0)
|
||||
points.bottomMidLeft = new Point(width, width)
|
||||
points.topMidRight = new Point(width * 1.5, 0)
|
||||
points.bottomMidRight = new Point(width * 1.5, width)
|
||||
points.topRight = new Point(length, 0)
|
||||
points.bottomRight = new Point(length, width)
|
||||
|
||||
if (complete) {
|
||||
paths.seam = new Path()
|
||||
.move(points.topMidLeft)
|
||||
.line(points.topLeft)
|
||||
.line(points.bottomLeft)
|
||||
.line(points.bottomMidLeft)
|
||||
.move(points.bottomMidRight)
|
||||
.line(points.bottomRight)
|
||||
.line(points.topRight)
|
||||
.line(points.topMidRight)
|
||||
.attr('class', 'fabric')
|
||||
paths.hint = new Path()
|
||||
.move(points.topMidLeft)
|
||||
.line(points.topMidRight)
|
||||
.move(points.bottomMidLeft)
|
||||
.line(points.bottomMidRight)
|
||||
.attr('class', 'fabric dashed')
|
||||
} else {
|
||||
paths.seam = new Path()
|
||||
.move(points.topLeft)
|
||||
.line(points.bottomLeft)
|
||||
.line(points.bottomRight)
|
||||
.line(points.topRight)
|
||||
.close()
|
||||
.attr('class', 'fabric')
|
||||
}
|
||||
|
||||
// Complete pattern?
|
||||
if (complete) {
|
||||
if (sa) {
|
||||
paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||
}
|
||||
points.title = points.bottomLeft.shiftFractionTowards(points.topRight, 0.5)
|
||||
macro('title', { at: points.title, nr: 6, title: 'hoodCenter' })
|
||||
macro('grainline', {
|
||||
from: points.topLeft.shift(-90, width / 2),
|
||||
to: points.topRight.shift(-90, width / 2)
|
||||
})
|
||||
// Always include this dimension as we don't print the entire part
|
||||
macro('hd', {
|
||||
from: points.bottomLeft,
|
||||
to: points.bottomRight,
|
||||
y: points.bottomRight.y + sa + 15,
|
||||
text: units(store.get('hoodCenterLength'))
|
||||
})
|
||||
// Paperless?
|
||||
if (paperless) {
|
||||
macro('vd', {
|
||||
from: points.bottomRight,
|
||||
to: points.topRight,
|
||||
x: points.topRight.x + sa + 15
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
149
packages/yuri/src/hoodside.js
Normal file
149
packages/yuri/src/hoodside.js
Normal file
|
@ -0,0 +1,149 @@
|
|||
export default function (part) {
|
||||
const {
|
||||
store,
|
||||
sa,
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
measurements,
|
||||
complete,
|
||||
paperless,
|
||||
macro
|
||||
} = part.shorthand()
|
||||
|
||||
const neckOpening = store.get('frontNeckSeamLength') + store.get('backNeckSeamLength')
|
||||
const hoodOpening = measurements.head
|
||||
const neckCutoutDelta = store.get('neckCutoutFront') - store.get('neckCutoutBack')
|
||||
store.set('hoodCenterWidth', measurements.head / 10)
|
||||
const halfCenterPanel = store.get('hoodCenterWidth') / 2
|
||||
points.topLeft = new Point(0, 0)
|
||||
points.topRight = new Point(neckOpening, 0)
|
||||
points.neckRight = new Point(neckOpening, (hoodOpening - halfCenterPanel) / 2)
|
||||
points.neckLeft = new Point(0, points.neckRight.y)
|
||||
points.frontLeft = points.neckLeft.shift(-90, neckCutoutDelta)
|
||||
points.frontEdge = points.neckRight.shift(-90, neckCutoutDelta)
|
||||
points.neckEdge = points.neckLeft.shift(0, halfCenterPanel)
|
||||
points.neckEdgeCp2 = new Point(points.neckRight.x / 2, points.neckEdge.y)
|
||||
points.frontEdgeCp1 = new Point(points.neckEdgeCp2.x, points.frontEdge.y)
|
||||
points.shoulderNotch = new Path()
|
||||
.move(points.neckEdge)
|
||||
.curve(points.neckEdgeCp2, points.frontEdgeCp1, points.frontEdge)
|
||||
.shiftAlong(store.get('backNeckSeamLength') - halfCenterPanel)
|
||||
points.hoodTop = new Point(points.shoulderNotch.x, points.topLeft.y)
|
||||
points.hoodTopCp2 = points.hoodTop.shift(180, points.neckEdge.y * 0.7)
|
||||
points.hoodRim = new Point(points.frontEdge.x, points.neckRight.y * 0.2)
|
||||
points.hoodTopCp1 = points.hoodTop.shift(0, points.hoodTop.dx(points.hoodRim) / 2)
|
||||
points.frontEdgeCp2 = points.frontEdge.shift(90, halfCenterPanel)
|
||||
points._tmp1 = new Path()
|
||||
.move(points.hoodRim)
|
||||
.curve(points.hoodRim, points.hoodTopCp1, points.hoodTop)
|
||||
.shiftAlong(2)
|
||||
.rotate(90, points.hoodRim)
|
||||
points.hoodRimCp = points.hoodRim.shiftTowards(points._tmp1, points.neckRight.y / 3)
|
||||
points.neckRoll = points.neckRight.shift(180, halfCenterPanel)
|
||||
points._tmp2 = new Path()
|
||||
.move(points.neckRoll)
|
||||
.curve(points.neckRoll, points.hoodRimCp, points.hoodRim)
|
||||
.shiftAlong(2)
|
||||
points.neckRollCp2 = points.neckRoll.shiftTowards(points._tmp2, halfCenterPanel)
|
||||
points.neckRollCp1 = points.neckRollCp2.rotate(180, points.neckRoll)
|
||||
|
||||
paths.seam = new Path()
|
||||
.move(points.frontEdge)
|
||||
.curve(points.frontEdgeCp2, points.neckRollCp1, points.neckRoll)
|
||||
.curve(points.neckRollCp2, points.hoodRimCp, points.hoodRim)
|
||||
.curve(points.hoodRim, points.hoodTopCp1, points.hoodTop)
|
||||
.curve(points.hoodTopCp2, points.neckEdge, points.neckEdge)
|
||||
.curve(points.neckEdgeCp2, points.frontEdgeCp1, points.frontEdge)
|
||||
.close()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
// Store length of center seam
|
||||
store.set(
|
||||
'hoodCenterLength',
|
||||
new Path()
|
||||
.move(points.hoodRim)
|
||||
.curve(points.hoodRim, points.hoodTopCp1, points.hoodTop)
|
||||
.curve(points.hoodTopCp2, points.neckEdge, points.neckEdge)
|
||||
.length()
|
||||
)
|
||||
|
||||
// Complete pattern?
|
||||
if (complete) {
|
||||
if (sa) {
|
||||
// Reversing this curve sidesteps a bezierjs edge case
|
||||
paths.sa = paths.seam
|
||||
.reverse()
|
||||
.offset(sa * -1)
|
||||
.attr('class', 'fabric sa')
|
||||
}
|
||||
points.title = points.hoodTop.shift(-90, 50)
|
||||
macro('title', { at: points.title, nr: 5, title: 'hoodSide' })
|
||||
points.logo = points.title.shift(-90, 60)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
macro('grainline', {
|
||||
from: points.shoulderNotch,
|
||||
to: points.hoodTop
|
||||
})
|
||||
}
|
||||
|
||||
// Paperless?
|
||||
if (paperless) {
|
||||
const neckSeam = new Path()
|
||||
.move(points.neckEdge)
|
||||
.curve(points.neckEdgeCp2, points.frontEdgeCp1, points.frontEdge)
|
||||
.split(points.shoulderNotch)
|
||||
const centralSeam = new Path()
|
||||
.move(points.hoodRim)
|
||||
.curve(points.hoodRim, points.hoodTopCp1, points.hoodTop)
|
||||
.curve(points.hoodTopCp2, points.neckEdge, points.neckEdge)
|
||||
.reverse()
|
||||
const openingSeam = new Path()
|
||||
.move(points.neckRoll)
|
||||
.curve(points.neckRollCp2, points.hoodRimCp, points.hoodRim)
|
||||
|
||||
macro('pd', {
|
||||
path: neckSeam[0],
|
||||
d: sa + 15
|
||||
})
|
||||
macro('pd', {
|
||||
path: neckSeam[1],
|
||||
d: sa + 15
|
||||
})
|
||||
macro('pd', {
|
||||
path: centralSeam,
|
||||
d: sa * -1 - 15
|
||||
})
|
||||
macro('hd', {
|
||||
from: points.neckEdge,
|
||||
to: points.frontEdge,
|
||||
y: points.frontEdge.y + sa + 30
|
||||
})
|
||||
macro('hd', {
|
||||
from: centralSeam.edge('left'),
|
||||
to: points.frontEdge,
|
||||
y: points.frontEdge.y + sa + 45
|
||||
})
|
||||
const openingEdge = openingSeam.edge('left')
|
||||
macro('hd', {
|
||||
from: openingEdge,
|
||||
to: points.frontEdge,
|
||||
y: openingEdge.y
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.frontEdge,
|
||||
to: points.hoodRim,
|
||||
x: points.hoodRim.x + sa + 15
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.frontEdge,
|
||||
to: points.hoodTop,
|
||||
x: points.hoodRim.x + sa + 30
|
||||
})
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
43
packages/yuri/src/index.js
Normal file
43
packages/yuri/src/index.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import freesewing from '@freesewing/core'
|
||||
import plugins from '@freesewing/plugin-bundle'
|
||||
import Brian from '@freesewing/brian'
|
||||
import config from '../config'
|
||||
// Parts
|
||||
import draftBack from './back'
|
||||
import draftFront from './front'
|
||||
import draftSleeve from './sleeve'
|
||||
import draftCuff from './cuff'
|
||||
import draftGusset from './gusset'
|
||||
import draftHoodSide from './hoodside'
|
||||
import draftHoodCenter from './hoodcenter'
|
||||
|
||||
// Create new design
|
||||
const Pattern = new freesewing.Design(config, plugins)
|
||||
|
||||
// Attach draft methods from Brian to prototype
|
||||
Pattern.prototype.draftBase = function (part) {
|
||||
return new Brian(this.settings).draftBase(part)
|
||||
}
|
||||
Pattern.prototype.draftFrontBase = function (part) {
|
||||
return new Brian(this.settings).draftFront(part)
|
||||
}
|
||||
Pattern.prototype.draftBackBase = function (part) {
|
||||
return new Brian(this.settings).draftBack(part)
|
||||
}
|
||||
Pattern.prototype.draftSleevecap = function (part) {
|
||||
return new Brian(this.settings).draftSleevecap(part)
|
||||
}
|
||||
Pattern.prototype.draftSleeveBase = function (part) {
|
||||
return new Brian(this.settings).draftSleeve(part)
|
||||
}
|
||||
|
||||
// Attach own draft methods to prototype
|
||||
Pattern.prototype.draftBack = draftBack
|
||||
Pattern.prototype.draftFront = draftFront
|
||||
Pattern.prototype.draftSleeve = draftSleeve
|
||||
Pattern.prototype.draftCuff = draftCuff
|
||||
Pattern.prototype.draftGusset = draftGusset
|
||||
Pattern.prototype.draftHoodSide = draftHoodSide
|
||||
Pattern.prototype.draftHoodCenter = draftHoodCenter
|
||||
|
||||
export default Pattern
|
165
packages/yuri/src/shared.js
Normal file
165
packages/yuri/src/shared.js
Normal file
|
@ -0,0 +1,165 @@
|
|||
export const sharedDimensions = function (part, s) {
|
||||
let { macro, Point, points, sa } = part.shorthand()
|
||||
|
||||
if (s === 'front') {
|
||||
points.cHem = points.cfHem
|
||||
points.cNeck = points.cfNeck
|
||||
} else {
|
||||
points.cHem = points.cbHem
|
||||
points.cNeck = points.cbNeck
|
||||
}
|
||||
|
||||
macro('hd', {
|
||||
from: points.cHem,
|
||||
to: points.hem,
|
||||
y: points.cHem.y + 3 * sa + 15,
|
||||
})
|
||||
macro('ld', {
|
||||
from: new Point(0, points.armholePitch.y),
|
||||
to: points.armholePitch,
|
||||
})
|
||||
macro('hd', {
|
||||
from: points.cNeck,
|
||||
to: points.neck,
|
||||
y: points.neck.y - sa - 15,
|
||||
})
|
||||
macro('hd', {
|
||||
from: points.cNeck,
|
||||
to: points.shoulder,
|
||||
y: points.neck.y - sa - 30,
|
||||
})
|
||||
macro('hd', {
|
||||
from: points.cNeck,
|
||||
to: points.armhole,
|
||||
y: points.neck.y - sa - 45,
|
||||
})
|
||||
macro('ld', {
|
||||
from: points.neck,
|
||||
to: points.shoulder,
|
||||
d: -15,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.hem,
|
||||
to: points.armhole,
|
||||
x: points.armhole.x + sa + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.armhole,
|
||||
to: points.armholePitch,
|
||||
x: points.armhole.x + sa + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.armholePitch,
|
||||
to: points.shoulder,
|
||||
x: points.armhole.x + sa + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.armhole,
|
||||
to: points.shoulder,
|
||||
x: points.armhole.x + sa + 30,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.armhole,
|
||||
to: points.neck,
|
||||
x: points.armhole.x + sa + 45,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.cNeck,
|
||||
to: points.neck,
|
||||
x: points.cNeck.x - 15,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.cHem,
|
||||
to: points.cNeck,
|
||||
x: points.cNeck.x - 15,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.cHem,
|
||||
to: points.neck,
|
||||
x: points.cNeck.x - 30,
|
||||
})
|
||||
}
|
||||
|
||||
export const draftRibbing = function (part, length) {
|
||||
let {
|
||||
store,
|
||||
measurements,
|
||||
options,
|
||||
points,
|
||||
paths,
|
||||
Path,
|
||||
Point,
|
||||
sa,
|
||||
complete,
|
||||
paperless,
|
||||
macro,
|
||||
units,
|
||||
} = part.shorthand()
|
||||
// Don't run this every time, except when sampling
|
||||
if (typeof store.get('ribbingHeight') === 'undefined' || part.context.settings.sample) {
|
||||
store.set(
|
||||
'ribbingHeight',
|
||||
(measurements.hpsToWaistBack + measurements.waistToHips) * options.ribbingHeight
|
||||
)
|
||||
}
|
||||
let height = store.get('ribbingHeight')
|
||||
let gap = 25
|
||||
let lead = 50
|
||||
if (length < 125) lead = length / 3
|
||||
|
||||
points.topLeft = new Point(0, 0)
|
||||
points.topRight = new Point(height * 2, 0)
|
||||
points.leftGapStart = new Point(0, lead)
|
||||
points.rightGapEnd = new Point(points.topRight.x, lead)
|
||||
points.leftGapEnd = new Point(0, lead + gap)
|
||||
points.rightGapStart = new Point(points.topRight.x, lead + gap)
|
||||
points.bottomLeft = new Point(0, gap + 2 * lead)
|
||||
points.bottomRight = new Point(points.topRight.x, gap + 2 * lead)
|
||||
|
||||
paths.seam = new Path()
|
||||
.move(points.rightGapEnd)
|
||||
.line(points.topRight)
|
||||
.line(points.topLeft)
|
||||
.line(points.leftGapStart)
|
||||
.move(points.leftGapEnd)
|
||||
.line(points.bottomLeft)
|
||||
.line(points.bottomRight)
|
||||
.line(points.rightGapStart)
|
||||
.attr('class', 'various')
|
||||
|
||||
paths.hint = new Path()
|
||||
.move(points.leftGapStart)
|
||||
.line(points.leftGapEnd)
|
||||
.move(points.rightGapStart)
|
||||
.line(points.rightGapEnd)
|
||||
.attr('class', 'various dashed')
|
||||
|
||||
if (complete) {
|
||||
points.title = new Point(points.bottomRight.x / 2, points.bottomRight.y / 2)
|
||||
if (sa) {
|
||||
paths.sa = new Path()
|
||||
.move(points.topLeft)
|
||||
.line(points.bottomLeft)
|
||||
.line(points.bottomRight)
|
||||
.line(points.topRight)
|
||||
.line(points.topLeft)
|
||||
.close()
|
||||
.offset(sa)
|
||||
.attr('class', 'various sa')
|
||||
}
|
||||
macro('vd', {
|
||||
from: points.bottomRight,
|
||||
to: points.topRight,
|
||||
x: points.topRight.x - 25,
|
||||
text: units(length),
|
||||
})
|
||||
}
|
||||
|
||||
if (paperless) {
|
||||
macro('hd', {
|
||||
from: points.topLeft,
|
||||
to: points.topRight,
|
||||
y: points.topRight.y - sa - 15,
|
||||
})
|
||||
}
|
||||
}
|
88
packages/yuri/src/sleeve.js
Normal file
88
packages/yuri/src/sleeve.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
export default function (part) {
|
||||
let {
|
||||
Point,
|
||||
Path,
|
||||
points,
|
||||
paths,
|
||||
store,
|
||||
options,
|
||||
complete,
|
||||
sa,
|
||||
paperless,
|
||||
macro,
|
||||
} = part.shorthand()
|
||||
|
||||
// Clear paths from Brian, but keep sleevecap
|
||||
for (let p of Object.keys(paths)) {
|
||||
if (p !== 'sleevecap') delete paths[p]
|
||||
}
|
||||
|
||||
// Shorten sleeve to take ribbing into account
|
||||
if (options.ribbing) {
|
||||
for (let p of ['wristLeft', 'wristRight'])
|
||||
points[p] = points[p].shift(90, store.get('ribbingHeight'))
|
||||
}
|
||||
|
||||
// Paths
|
||||
paths.saBase = new Path()
|
||||
.move(points.wristRight)
|
||||
.line(points.bicepsRight)
|
||||
.join(paths.sleevecap)
|
||||
.line(points.wristLeft)
|
||||
.attr('class', 'various stroke-xxl')
|
||||
paths.hemBase = new Path()
|
||||
.move(points.wristLeft)
|
||||
.line(points.wristRight)
|
||||
.attr('class', 'various stroke-xxl')
|
||||
paths.saBase.render = false
|
||||
paths.hemBase.render = false
|
||||
|
||||
paths.seam = paths.saBase.join(paths.hemBase).close().attr('class', 'fabric')
|
||||
|
||||
// Complete?
|
||||
if (complete) {
|
||||
macro('grainline', {
|
||||
from: new Point(0, points.wristLeft.y),
|
||||
to: new Point(0, points.backPitch.y),
|
||||
})
|
||||
if (sa) {
|
||||
if (options.ribbing) paths.sa = paths.seam.offset(sa)
|
||||
else {
|
||||
paths.sa = paths.saBase
|
||||
.clone()
|
||||
.offset(sa)
|
||||
.join(paths.hemBase.offset(3 * sa))
|
||||
.close()
|
||||
}
|
||||
paths.sa.attr('class', 'fabric sa')
|
||||
}
|
||||
}
|
||||
|
||||
// Paperless?
|
||||
if (paperless) {
|
||||
let hemSa = sa
|
||||
if (!options.ribbing) hemSa = 3 * sa
|
||||
macro('hd', {
|
||||
from: points.wristLeft,
|
||||
to: points.wristRight,
|
||||
y: points.wristLeft.y + hemSa + 15,
|
||||
})
|
||||
macro('hd', {
|
||||
from: points.bicepsLeft,
|
||||
to: points.bicepsRight,
|
||||
y: points.sleeveTip.y - sa - 15,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.wristLeft,
|
||||
to: points.bicepsLeft,
|
||||
x: points.bicepsLeft.x - sa - 15,
|
||||
})
|
||||
macro('vd', {
|
||||
from: points.wristLeft,
|
||||
to: points.sleeveTip,
|
||||
x: points.bicepsLeft.x - sa - 30,
|
||||
})
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue