✨ Added @freesewing/utils
This commit is contained in:
parent
d8cc1f76f3
commit
e7b7c5a7dd
18 changed files with 393 additions and 0 deletions
98
packages/utils/README.md
Normal file
98
packages/utils/README.md
Normal file
|
@ -0,0 +1,98 @@
|
|||
> **Note**: This is part of version 2 of FreeSewing.
|
||||
> It is a work in progress, and not ready for prime-time yet
|
||||
>
|
||||
> For all questions, please come say hello in [our chatroom on Gitter](https://gitter.im/).
|
||||
|
||||
<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></p>
|
||||
<p align="center">FreeSewing is a free and open source library for made-to-measure sewing patterns</p>
|
||||
<p align='center'><a
|
||||
href="https://www.npmjs.com/package/@freesewing/utils"
|
||||
title="@freesewing/utils on NPM"
|
||||
><img src="https://img.shields.io/npm/v/freesewing.svg"
|
||||
alt="@freesewing/utils on NPM"/>
|
||||
</a><a
|
||||
href="https://opensource.org/licenses/MIT"
|
||||
title="License: MIT"
|
||||
><img src="https://img.shields.io/npm/l/freesewing.svg?label=License"
|
||||
alt="License: MIT"/>
|
||||
</a><a
|
||||
href="https://github.com/freesewing/freesewing/issues?q=is%3Aissue+is%3Aopen+label%3Apkg%3Autils"
|
||||
title="Open issues tagged pkg:utils"
|
||||
><img src="https://img.shields.io/github/issues/freesewing/freesewing/pkg:utils.svg?label=Issues"
|
||||
alt="Open issues tagged pkg:utils"/>
|
||||
</a></p><p align='center'><a
|
||||
href="https://twitter.com/freesewing_org"
|
||||
title="Follow @freesewing_org on Twitter"
|
||||
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Follow%20us-blue.svg?logo=twitter&logoColor=white&logoWidth=15"
|
||||
alt="Follow @freesewing_org on Twitter"/>
|
||||
</a><a
|
||||
href="https://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>
|
||||
|
||||
# @freesewing/utils
|
||||
|
||||
A collection of utilities shared across freesewing frontend projects
|
||||
|
||||
|
||||
|
||||
## 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).
|
46
packages/utils/package.json
Normal file
46
packages/utils/package.json
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "@freesewing/utils",
|
||||
"version": "0.33.0",
|
||||
"description": "A collection of utilities shared across freesewing frontend projects",
|
||||
"author": "Joost De Cock <joost@decock.org> (https://github.com/joostdecock)",
|
||||
"homepage": "https://freesewing.org/",
|
||||
"repository": "github:freesewing/freesewing",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/freesewing/freesewing/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"freesewing",
|
||||
"design",
|
||||
"diy",
|
||||
"fashion",
|
||||
"made to measure",
|
||||
"parametric design",
|
||||
"sewing"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
"scripts": {
|
||||
"clean": "rimraf ../../dist/utils",
|
||||
"nodebuild": "BABEL_ENV=production rollup -c -o ../../dist/utils/index.js -f cjs",
|
||||
"modulebuild": "BABEL_ENV=production rollup -c -o ../../dist/utils/index.mjs -f es",
|
||||
"build": "npm run clean && npm run nodebuild && npm run modulebuild",
|
||||
"test": "echo \"utils: No tests configured. Perhaps you'd like to do this?\" && exit 0",
|
||||
"pubtest": "npm publish --registry http://localhost:6662"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"files": [
|
||||
"../../dist/packages/utils/*",
|
||||
"README.md",
|
||||
"package.json"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0",
|
||||
"npm": ">=5"
|
||||
}
|
||||
}
|
29
packages/utils/rollup.config.js
Normal file
29
packages/utils/rollup.config.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import babel from "rollup-plugin-babel";
|
||||
import resolve from "rollup-plugin-node-resolve";
|
||||
import json from "rollup-plugin-json";
|
||||
import minify from "rollup-plugin-babel-minify";
|
||||
import yaml from "rollup-plugin-yaml";
|
||||
import peerDepsExternal from "rollup-plugin-peer-deps-external";
|
||||
import { name, version, description, author, license } from "./package.json";
|
||||
|
||||
export default {
|
||||
input: "src/index.js",
|
||||
output: {
|
||||
sourcemap: true
|
||||
},
|
||||
plugins: [
|
||||
peerDepsExternal(),
|
||||
resolve({ modulesOnly: true }),
|
||||
json(),
|
||||
yaml(),
|
||||
babel({
|
||||
exclude: "node_modules/**",
|
||||
plugins: ["@babel/plugin-proposal-object-rest-spread"]
|
||||
}),
|
||||
minify({
|
||||
comments: false,
|
||||
sourceMap: true,
|
||||
banner: `/**\n * ${name} | v${version}\n * ${description}\n * (c) ${new Date().getFullYear()} ${author}\n * @license ${license}\n */`
|
||||
})
|
||||
]
|
||||
};
|
3
packages/utils/src/cloneObject.js
Normal file
3
packages/utils/src/cloneObject.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const cloneObject = src => Object.assign({}, src);
|
||||
|
||||
export default cloneObject;
|
15
packages/utils/src/defaultGist.js
Normal file
15
packages/utils/src/defaultGist.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
const defaultGist = {
|
||||
settings: {
|
||||
embed: true,
|
||||
sa: 0,
|
||||
complete: true,
|
||||
paperless: false,
|
||||
locale: "en",
|
||||
units: "metric",
|
||||
margin: 2,
|
||||
measurements: {},
|
||||
options: {}
|
||||
}
|
||||
};
|
||||
|
||||
export default defaultGist;
|
6
packages/utils/src/defaultSa.js
Normal file
6
packages/utils/src/defaultSa.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
const defaultSa = {
|
||||
imperial: 15.875,
|
||||
metric: 10
|
||||
};
|
||||
|
||||
export default defaultSa;
|
17
packages/utils/src/formatImperial.js
Normal file
17
packages/utils/src/formatImperial.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
const formatImperial = (
|
||||
neg,
|
||||
inch,
|
||||
numo = false,
|
||||
deno = false,
|
||||
format = "html"
|
||||
) => {
|
||||
if (format === "html") {
|
||||
if (numo) return `<span>${neg}${inch}<sup>${numo}</sup>/<sub>${deno}</sub></span>`;
|
||||
else return `<span>{neg}{inch}</span>`;
|
||||
} else {
|
||||
if (numo) return `${neg}${inch}`;
|
||||
else return `${neg}${inch} ${numo}/${deno}`;
|
||||
}
|
||||
};
|
||||
|
||||
export default formatImperial;
|
43
packages/utils/src/formatMm.js
Normal file
43
packages/utils/src/formatMm.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import roundMm from "./roundMm";
|
||||
import formatImperial from "./formatImperial";
|
||||
|
||||
const formatMm = (val, units, format = "html") => {
|
||||
val = roundMm(val);
|
||||
let H = format === "html" ? true : false;
|
||||
if (units === "imperial") {
|
||||
if (val == 0) return formatImperial("", 0, false, false, format);
|
||||
let negative = "";
|
||||
let inches = "";
|
||||
let rest = "";
|
||||
let fraction = val / 25.4;
|
||||
if (fraction < 0) {
|
||||
fraction = fraction * -1;
|
||||
negative = "-";
|
||||
}
|
||||
if (Math.abs(fraction) < 1) rest = fraction;
|
||||
else {
|
||||
inches = Math.floor(fraction);
|
||||
rest = fraction - inches;
|
||||
}
|
||||
let fraction128 = Math.round(rest * 128);
|
||||
if (fraction128 == 0) return formatImperial(negative, inches);
|
||||
if (fraction128 % 64 == 0)
|
||||
return formatImperial(negative, inches, fraction128 / 64, 2);
|
||||
if (fraction128 % 32 == 0)
|
||||
return formatImperial(negative, inches, fraction128 / 32, 4);
|
||||
if (fraction128 % 16 == 0)
|
||||
return formatImperial(negative, inches, fraction128 / 16, 8);
|
||||
if (fraction128 % 8 == 0)
|
||||
return formatImperial(negative, inches, fraction128 / 8, 16);
|
||||
if (fraction128 % 4 == 0)
|
||||
return formatImperial(negative, inches, fraction128 / 4, 32);
|
||||
if (fraction128 % 2 == 0)
|
||||
return formatImperial(negative, inches, fraction128 / 2, 64);
|
||||
return negative + fraction;
|
||||
} else {
|
||||
if (format === "html") return roundMm(val / 10) + "cm";
|
||||
else return roundMm(val / 10);
|
||||
}
|
||||
};
|
||||
|
||||
export default formatMm;
|
29
packages/utils/src/gistDefaults.js
Normal file
29
packages/utils/src/gistDefaults.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import defaultGist from "./defaultGist";
|
||||
import optionDefault from "./optionDefault";
|
||||
|
||||
const gistDefaults = (config, gist = false) => {
|
||||
if (!gist) gist = defaultGist;
|
||||
let options = {};
|
||||
for (let option of Object.keys(config.options)) {
|
||||
if (
|
||||
typeof gist.options !== "undefined" &&
|
||||
typeof gist.options[option] !== undefined
|
||||
)
|
||||
options[option] = gist.options[option];
|
||||
else options[option] = optionDefault(config.options[option]);
|
||||
}
|
||||
delete gist.options;
|
||||
let settings = JSON.parse(JSON.stringify(defaultGist.settings));
|
||||
delete settings.locale;
|
||||
delete settings.units;
|
||||
for (let setting of Object.keys(settings)) {
|
||||
if (typeof gist.settings[setting] !== "undefined") {
|
||||
settings[setting] = gist.settings[setting];
|
||||
}
|
||||
}
|
||||
settings.options = options;
|
||||
|
||||
return settings;
|
||||
};
|
||||
|
||||
export default gistDefaults;
|
14
packages/utils/src/index.js
Normal file
14
packages/utils/src/index.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
export { default as smallestImperialStep } from "./smallestImperialStep";
|
||||
export { default as roundMm } from "./roundMm";
|
||||
export { default as roundMmDown } from "./roundMmDown";
|
||||
export { default as roundMmUp } from "./roundMmUp";
|
||||
export { default as formatImperial } from "./formatImperial";
|
||||
export { default as formatMm } from "./formatMm";
|
||||
export { default as defaultSa } from "./defaultSa";
|
||||
export { default as sliderStep } from "./sliderStep";
|
||||
export { default as optionType } from "./optionType";
|
||||
export { default as defaultGist } from "./defaultGist";
|
||||
export { default as gistDefaults } from "./gistDefaults";
|
||||
export { default as optionDefault } from "./optionDefault";
|
||||
export { default as storage } from "./storage";
|
||||
export { default as cloneObject } from "./cloneObject";
|
17
packages/utils/src/optionDefault.js
Normal file
17
packages/utils/src/optionDefault.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import optionType from "./optionType";
|
||||
|
||||
const optionDefault = option => {
|
||||
let type = optionType(option);
|
||||
switch (optionType(option)) {
|
||||
case "constant":
|
||||
return option;
|
||||
break;
|
||||
case "list":
|
||||
return option.dflt;
|
||||
break;
|
||||
default:
|
||||
return option[type];
|
||||
}
|
||||
};
|
||||
|
||||
export default optionDefault;
|
15
packages/utils/src/optionType.js
Normal file
15
packages/utils/src/optionType.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
const optionType = option => {
|
||||
if (typeof option === "object") {
|
||||
if (typeof option.pct !== "undefined") return "pct";
|
||||
if (typeof option.mm !== "undefined") return "mm";
|
||||
if (typeof option.deg !== "undefined") return "deg";
|
||||
if (typeof option.count !== "undefined") return "count";
|
||||
if (typeof option.bool !== "undefined") return "bool";
|
||||
if (typeof option.list !== "undefined") return "list";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
return "constant";
|
||||
};
|
||||
|
||||
export default optionType;
|
8
packages/utils/src/roundMm.js
Normal file
8
packages/utils/src/roundMm.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
const roundMm = (val, units) => {
|
||||
if (units === "imperial")
|
||||
return Math.round(val * 1000000) / 1000000;
|
||||
else
|
||||
return Math.round(val * 10) / 10;
|
||||
};
|
||||
|
||||
export default roundMm;
|
10
packages/utils/src/roundMmDown.js
Normal file
10
packages/utils/src/roundMmDown.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import smallestImperialStep from "./smallestImperialStep";
|
||||
|
||||
const roundMmDown = (val, units) => {
|
||||
if (units === "imperial")
|
||||
return val - (val % smallestImperialStep);
|
||||
else
|
||||
return Math.floor(val * 10) / 10;
|
||||
};
|
||||
|
||||
export default roundMmDown;
|
10
packages/utils/src/roundMmUp.js
Normal file
10
packages/utils/src/roundMmUp.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import smallestImperialStep from "./smallestImperialStep";
|
||||
|
||||
const roundMmUp = (val, units) => {
|
||||
if (units === "imperial")
|
||||
return val - (val % smallestImperialStep);
|
||||
else
|
||||
return Math.ceil(val * 10) / 10;
|
||||
};
|
||||
|
||||
export default roundMmUp;
|
6
packages/utils/src/sliderStep.js
Normal file
6
packages/utils/src/sliderStep.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
const sliderStep = {
|
||||
metric: 0.1,
|
||||
imperial: 0.396875
|
||||
};
|
||||
|
||||
export default sliderStep;
|
3
packages/utils/src/smallestImperialStep.js
Normal file
3
packages/utils/src/smallestImperialStep.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const smallestImperialStep = 0.396875;
|
||||
|
||||
export default smallestImperialStep;
|
24
packages/utils/src/storage.js
Normal file
24
packages/utils/src/storage.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
const storage = {
|
||||
set: (key, value, raw) => {
|
||||
if (typeof localStorage === "undefined")
|
||||
throw(new Error("No localStorage support. And we need it. Bailing out."));
|
||||
|
||||
const _key = "fs_" + key;
|
||||
|
||||
if (typeof value === "undefined" || value === null)
|
||||
localStorage.removeItem(_key);
|
||||
else localStorage.setItem(_key, raw ? value : JSON.stringify(value));
|
||||
|
||||
return value;
|
||||
},
|
||||
get: (key, raw) => {
|
||||
if (typeof localStorage === "undefined")
|
||||
throw(new Error("No localStorage support. And we need it. Bailing out."));
|
||||
|
||||
const value = localStorage.getItem("fs_"+key);
|
||||
|
||||
return raw ? value : JSON.parse(value);
|
||||
}
|
||||
}
|
||||
|
||||
export default storage;
|
Loading…
Add table
Add a link
Reference in a new issue