1
0
Fork 0

🚚 Post lerna init and import of packages

This commit is contained in:
Joost De Cock 2019-04-19 08:37:33 +02:00
parent d73cd3512c
commit 921a757356
48 changed files with 14830 additions and 0 deletions

15
lerna.json Normal file
View file

@ -0,0 +1,15 @@
{
"version": "0.0.0",
"npmClient": "npm",
"command": {
"publish": {
"ignoreChanges": ["ignored-file", "*.md"],
"message": "chore(release): publish"
},
"bootstrap": {
"ignore": "component-*",
"npmClientArgs": ["--no-package-lock"]
}
},
"packages": ["packages/*"]
}

7
package.json Normal file
View file

@ -0,0 +1,7 @@
{
"name": "root",
"private": true,
"devDependencies": {
"lerna": "^3.13.3"
}
}

View file

@ -0,0 +1,13 @@
# editorconfig.org
root = true
[*]
indent_size = 2
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

66
packages/components/.gitignore vendored Normal file
View file

@ -0,0 +1,66 @@
# Compiled code
dist
tests/dist
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
coverage.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next

View file

@ -0,0 +1 @@
dist/

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 freesewing
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.

View file

@ -0,0 +1,57 @@
<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>
<h4 align="center"><em>&nbsp;<a title="Go to freesewing.org" href="https://freesewing.org/">freesewing</a></em>
<br><sup>a library for made-to-measure sewing patterns</sup>
</h4>
<p align="center">
<a href="https://www.npmjs.com/package/@freesewing/components"><img src="https://badgen.net/npm/v/@freesewing/components" alt="Version"></a>
<a href="https://www.npmjs.com/package/@freesewing/components"><img src="https://badgen.net/npm/license/@freesewing/components" alt="License"></a>
<a href="https://deepscan.io/dashboard#view=project&tid=2114&pid=4633&bid=37171"><img src="https://deepscan.io/api/teams/2114/projects/4633/branches/37171/badge/grade.svg" alt="DeepScan grade"></a>
<a href="https://gitter.im/freesewing/freesewing"><img src="https://badgen.net/badge/chat/on%20Gitter/cyan" alt="Chat on Gitter"></a>
<a href="https://freesewing.org/patrons/join"><img src="https://badgen.net/badge/become/a%20Patron/FF5B77" alt="Become a Patron"></a>
</p>
# @freesewing/components
This is a [Material UI](https://material-ui.com) theme that's used by the freesewing web sites.
## Install
```
npm i --save @freesewing/components
```
## Getting the theme
After installing [@freesewing/components](https://www.npmjs.com/package/@freesewing/components),
import it:
```js
import createTheme from "@freesewing/components";
```
The default export (`createTheme` in our example above) is a method that
calls [`createMuiTheme`](https://material-ui.com/customization/themes/#createmuitheme-options-theme) under the hood.
It takes a single argument, the theme name:
```
object createTheme(string themeName = "light")
```
If the name you pass it is `dark` you'll get the dark theme.
Anything else, and you'll get the light theme.
## Using the theme
To use this theme, you need to pass it as the `theme` prop to
[`muiThemeProvider`](https://material-ui.com/customization/themes/#muithemeprovider):
```js
<MuiThemeProvider theme={createTheme(true)}>
// ... your app here
</MuiThemeProvider>
```
See [the Material-UI docs on themes](https://material-ui.com/customization/themes/) for more details.

View file

@ -0,0 +1,70 @@
{
"name": "@freesewing/components",
"version": "0.0.1",
"description": "A collection of React components for freesewing web UIs",
"author": "Joost De Cock <joost@decock.org> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/freesewing/components.git"
},
"bugs": {
"url": "https://github.com/freesewing/components/issues"
},
"main": "dist/index.js",
"module": "dist/index.mjs",
"scripts": {
"patch": "npm version patch -m ':bookmark: v%s' && npm run build",
"minor": "npm version minor -m ':bookmark: v%s' && npm run build",
"major": "npm version major -m ':bookmark: v%s' && npm run build",
"precommit": "npm run pretty && lint-staged",
"clean": "rimraf dist",
"pretty": "npx prettier --write 'src/*.js'",
"lint": "eslint --fix 'src/*.js'",
"nodebuild": "rollup --silent -c -o dist/index.js -f cjs -e bezier-js,bin-pack",
"modulebuild": "rollup --silent -c -o dist/index.mjs -f esm",
"build": "npm run clean && npm run nodebuild && npm run modulebuild"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,json}": [
"prettier --write",
"git add"
]
},
"dependencies": {},
"devDependencies": {
"@babel/core": "7.3.3",
"@babel/plugin-proposal-object-rest-spread": "7.4.3",
"@babel/preset-env": "7.3.1",
"babel-eslint": "^8.2.6",
"eslint": "5.14.0",
"eslint-config-prettier": "^2.10.0",
"eslint-config-standard": "12.0.0",
"eslint-plugin-import": "2.15.0",
"eslint-plugin-node": "8.0.1",
"eslint-plugin-prettier": "2.7.0",
"eslint-plugin-promise": "4.0.1",
"eslint-plugin-standard": "4.0.0",
"husky": "^0.14.3",
"lint-staged": "^7.3.0",
"prettier": "1.16.4",
"rimraf": "2.6.3",
"rollup": "0.63.4",
"rollup-plugin-babel": "4.3.2",
"rollup-plugin-commonjs": "9.2.0",
"rollup-plugin-json": "^3.1.0",
"rollup-plugin-node-resolve": "^3.4.0",
"rollup-plugin-terser": "^1.0.1"
},
"files": [
"dist/*",
"README.md",
"package.json"
]
}

View file

@ -0,0 +1,27 @@
import React from "react";
import PropTypes from "prop-types";
const Emblem = props => (
<React.Fragment>
<span className="emb" style={{color: props.c1}}>{props.t1}</span>
<span className="lem" style={{color: props.c2}}>{props.t2}</span>
</React.Fragment>
);
Emblem.propTypes = {
size: PropTypes.number,
c1: PropTypes.string,
c2: PropTypes.string,
t1: PropTypes.string,
t2: PropTypes.string,
};
Emblem.defaultProps = {
size: 24,
c1: "#111111",
c2: "#111111",
t1: "",
t2: ""
};
export default Emblem;

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
{
"presets": [
["env", {
"modules": false
}],
"stage-0",
"react"
],
"plugins": [
["transform-object-rest-spread", { "useBuiltIns": true }]
]
}

View 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

View 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
}
}

22
packages/workbench/.gitignore vendored Normal file
View file

@ -0,0 +1,22 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
node_modules
# builds
build
dist
.rpt2_cache
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View file

@ -0,0 +1,4 @@
language: node_js
node_js:
- 9
- 8

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 freesewing
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.

View file

@ -0,0 +1,31 @@
# workbench
> A React component to facilitate freesewing pattern design
[![NPM](https://img.shields.io/npm/v/workbench.svg)](https://www.npmjs.com/package/workbench) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
## Install
```bash
npm install --save workbench
```
## Usage
```jsx
import React, { Component } from 'react'
import MyComponent from 'workbench'
class Example extends Component {
render () {
return (
<MyComponent />
)
}
}
```
## License
MIT © [freesewing](https://github.com/freesewing)

View file

@ -0,0 +1,5 @@
{
"plugins": [
["transform-object-rest-spread", { "useBuiltIns": true }]
]
}

File diff suppressed because it is too large Load diff

11122
packages/workbench/example/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,25 @@
{
"name": "workbench-example",
"homepage": "https://freesewing.github.io/workbench",
"version": "0.0.0",
"license": "MIT",
"private": true,
"dependencies": {
"@freesewing/aaron": "0.14.0",
"@freesewing/brian": "0.25.0",
"@freesewing/plugin-bundle": "0.9.0",
"freesewing": "0.31.0",
"prop-types": "^15.6.2",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-scripts": "^1.1.4",
"workbench": "file:.."
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {}
}

View file

@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<title>workbench</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>

View file

@ -0,0 +1,8 @@
{
"short_name": "workbench",
"name": "workbench",
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View file

@ -0,0 +1,15 @@
import React from 'react'
import Workbench from 'workbench'
import freesewing from "freesewing";
import Aaron from "@freesewing/aaron";
import Brian from "@freesewing/brian";
import bundle from "@freesewing/plugin-bundle";
export default props => <Workbench
freesewing={freesewing}
patterns={{
Aaron,
Brian
}}
plugins={{bundle}}
/>

View file

@ -0,0 +1,5 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))

View file

@ -0,0 +1,81 @@
{
"name": "@freesewing/workbench",
"version": "0.0.1",
"description": "A React component to facilitate freesewing pattern design",
"author": "Joost De Cock <joost@decock.org> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"license": "MIT",
"repository": "freesewing/workbench",
"bugs": {
"url": "https://github.com/freesewing/workbench/issues"
},
"main": "dist/index.js",
"module": "dist/index.es.js",
"jsnext:main": "dist/index.es.js",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"scripts": {
"patch": "npm version patch -m ':bookmark: v%s' && npm run build",
"minor": "npm version minor -m ':bookmark: v%s' && npm run build",
"major": "npm version major -m ':bookmark: v%s' && npm run build",
"test": "cross-env CI=1 react-scripts test --env=jsdom",
"test:watch": "react-scripts test --env=jsdom",
"build": "rollup -c",
"start": "rollup -c -w",
"prepare": "npm run build",
"predeploy": "cd example && npm install && npm run build",
"deploy": "gh-pages -d example/build"
},
"peerDependencies": {
"prop-types": "^15.5.4",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0"
},
"devDependencies": {
"@svgr/rollup": "^2.4.1",
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.5",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"cross-env": "^5.1.4",
"eslint": "^5.0.1",
"eslint-config-standard": "^11.0.0",
"eslint-config-standard-react": "^6.0.0",
"eslint-plugin-import": "^2.13.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.0",
"eslint-plugin-react": "^7.10.0",
"eslint-plugin-standard": "^3.1.0",
"gh-pages": "^1.2.0",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-scripts": "^1.1.4",
"rollup": "^0.64.1",
"rollup-plugin-babel": "^3.0.7",
"rollup-plugin-commonjs": "^9.1.3",
"rollup-plugin-json": "4.0.0",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-peer-deps-external": "^2.2.0",
"rollup-plugin-postcss": "^1.6.2",
"rollup-plugin-url": "^1.4.0"
},
"files": [
"dist"
],
"dependencies": {
"@freesewing/i18n": "0.11.3",
"@freesewing/mui-theme": "0.1.2",
"@freesewing/plugin-theme": "0.18.4",
"@material-ui/core": "3.9.2",
"@material-ui/icons": "3.0.2",
"freesewing": "0.30.6",
"material-icons": "0.3.1",
"react-intl": "2.8.0",
"typeface-roboto-condensed": "0.0.54"
}
}

View file

@ -0,0 +1,41 @@
import babel from 'rollup-plugin-babel'
import commonjs from 'rollup-plugin-commonjs'
import external from 'rollup-plugin-peer-deps-external'
import postcss from 'rollup-plugin-postcss'
import resolve from 'rollup-plugin-node-resolve'
import url from 'rollup-plugin-url'
import svgr from '@svgr/rollup'
import json from "rollup-plugin-json";
import pkg from './package.json'
export default {
input: 'src/index.js',
output: [
{
file: pkg.main,
format: 'cjs',
sourcemap: true
},
{
file: pkg.module,
format: 'es',
sourcemap: true
}
],
plugins: [
external(),
json(),
postcss({
modules: true
}),
url(),
svgr(),
babel({
exclude: 'node_modules/**',
plugins: [ 'external-helpers', 'transform-object-rest-spread' ]
}),
resolve({ browser: true }),
commonjs()
]
}

View file

@ -0,0 +1,5 @@
{
"env": {
"jest": true
}
}

View file

@ -0,0 +1,40 @@
import React from "react";
import Logo from "./Logo";
import Emblem from "./Emblem";
import { i18n } from "@freesewing/i18n";
import { version } from "../../package.json";
import { FormattedMessage } from "react-intl";
import css from "./css/ButtonPicker.css";
const ButtonPicker = props => (
<section>
<div className={css.box}>
<Logo size={250}/>
{ props.msgKey
? <h1><FormattedMessage id={props.msgKey} /></h1>
: <div><Emblem size={52} color1="#61dafb" color2="#ffffff" text1="Free" text2="Sewing"/></div>
}
<div className={css.buttons}>
{props.keys.map((key) => (
<button key={key} className={css.picker} onClick={() => props.setChoice(key)}>
<Emblem size={21} color1="#ffffff" text1={props.values[key]} text2=""/>
</button>
)
)}
</div>
</div>
<footer className={css.picker}>
Freesewing workbench v{version}
<br />
<a className={css.link} href="https://freesewing.org">
<Emblem size={16} color1="#61dafb" color2="#ffffff" text1="freesewing" text2=".org"/>
</a>
|
<a className={css.link} href="https://freesewing.dev">
<Emblem size={16} color1="#61dafb" color2="#ffffff" text1="freesewing" text2=".dev"/>
</a>
</footer>
</section>
);
export default ButtonPicker;

View file

@ -0,0 +1,47 @@
import React from "react";
import PropTypes from "prop-types";
const Emblem = props => {
const font = {
fontFamily: "'Roboto Condensed', sans-serif",
fontSize: props.size,
fontWeight: 900,
}
const styles = {
free: {
...font,
color: props.color1,
letterSpacing: props.size/-40+"px",
},
sewing: {
...font,
color: props.color2,
letterSpacing: props.size/-20+"px",
},
}
return (
<React.Fragment>
<span style={styles.free}>{props.text1}</span>
<span style={styles.sewing}>{props.text2}</span>
</React.Fragment>
);
};
Emblem.propTypes = {
size: PropTypes.number,
color1: PropTypes.string,
color2: PropTypes.string,
text1: PropTypes.string,
text2: PropTypes.string,
};
Emblem.defaultProps = {
size: 24,
color1: "#111111",
color2: "#111111",
text1: "",
text2: ""
};
export default Emblem;

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,44 @@
import React from "react";
import Logo from "./Logo";
import Emblem from "./Emblem";
import css from "./css/NavBar.css";
import { FormattedMessage } from "react-intl";
const NavBar = props => {
const goToHelp = () =>
window.location.href = "https://freesewing.dev/"+props.locale+"/workbench";
return (
<header className={css.navbar}>
{ props.empty
? ""
: <React.Fragment>
<div className={css.logo}><Logo size={36} /></div>
<a href="https://freesewing.org/" className={css.navbar}>
<Emblem size={20} color1="#61dafb" color2="#ffffff" text1="Free" text2="Sewing"/>
</a>
<div className={css.right}>
{ props.pattern ? (
<React.Fragment>
<button className={css.navbar} onClick={props.toggleSettings}>
<Emblem size={16} text1={<FormattedMessage id="app.settings" />} color1="#fff" />
</button>
<button className={css.navbar} onClick={props.clearPattern}>
<Emblem size={16} text1={props.pattern} color1="#fff" />
</button>
</React.Fragment>
) : ""
}
<button className={css.navbar} onClick={props.clearLanguage}>
<Emblem size={16} text1={props.language} color1="#fff" />
</button>
<button className={css.navbar} onClick={goToHelp}>
<Emblem size={16} text1="?" color1="#fff" />
</button>
</div>
</React.Fragment>
}
</header>
);
}
export default NavBar;

View file

@ -0,0 +1,21 @@
import React from "react";
import PropTypes from "prop-types";
const Pattern = props => {
return (
<React.Fragment>
<span style={styles.free}>{props.text1}</span>
<span style={styles.sewing}>{props.text2}</span>
</React.Fragment>
);
};
Pattern.propTypes = {
pattern: PropTypes.string,
freesewing: PropTypes.object
};
Pattern.defaultProps = {
};
export default Pattern;

View file

@ -0,0 +1,31 @@
.box {
text-align: center;
width: 100%;
}
.buttons {
padding: 1rem 2rem;
margin-top: 2rem;
}
button.picker {
padding: 0.5rem 1rem;
margin: 0.5rem 1rem;
border: 1px solid transparent;
border-bottom: 4px solid #fff6;
background: transparent;
}
button.picker:hover {
border-bottom: 4px solid #61dafb;
}
footer.picker {
position: fixed;
bottom: 2rem;
left: 0;
width: 100%;
text-align: center;
font-weight: bold;
}
.link {
padding: 0.5rem;
font-weight: normal;
}

View file

@ -0,0 +1,42 @@
div.config {
border: 1px solid #fffa;
border-radius: 4px;
padding: 1rem;
margin: 0.5rem;
}
table.config {
width: 300px;
text-align: left;
}
table.config td {
padding: 0.1rem 0.5rem;
}
td.option {
padding-left: 1rem;
}
span.key,
span.subkey {
font-weight: bold;
padding-right: 0.5rem;
}
span.true,
span.false {
font-family: 'Roboto Condensed', sans-serif;
font-weight: bold;
}
span.true {
color: #58fc58;
}
span.false {
color: #f97070;
}
span.key {
color: #61dafb;
font-family: 'Roboto Condensed', sans-serif;
}
ul.config,
ol.config {
margin: 0.2rem 0;
padding-left: 1.5rem;
}

View file

@ -0,0 +1,31 @@
.box {
text-align: center;
width: 100%;
}
.buttons {
padding: 1rem 2rem;
margin-top: 2rem;
}
button.picker {
padding: 0.5rem 1rem;
margin: 0.5rem 1rem;
border: 1px solid transparent;
border-bottom: 4px solid #fff6;
background: transparent;
}
button.picker:hover {
border-bottom: 4px solid #61dafb;
}
footer.picker {
position: fixed;
bottom: 2rem;
left: 0;
width: 100%;
text-align: center;
font-weight: bold;
}
.link {
padding: 0.5rem;
font-weight: normal;
}

View file

@ -0,0 +1,43 @@
header.navbar {
height: 64px;
background: #222;
color: #fff;
padding: 0 2rem;
display: flex;
align-items: center;
}
div.right {
flex-grow: 1;
text-align: right;
}
div.logo {
line-height: 0
}
button.emblem {
margin: 0;
margin-left: 1rem;
padding: 0 0.5rem;
height: 64px;
background: transparent;
border: 0;
border-bottom: 4px solid transparent;
transition: border 0.2s ease-out;
}
a.navbar,
button.navbar {
margin: 0;
margin-left: 1rem;
padding: 0 0.5rem;
height: 64px;
background: transparent;
border: 0;
border-bottom: 4px solid transparent;
transition: border 0.2s ease-out;
}
button.navbar:hover {
border-bottom: 4px solid #61dafb;
}
a.navbar {
line-height: 64px
}

View file

@ -0,0 +1,4 @@
div.wrapper {
padding: 1rem;
display: flex;
}

View file

@ -0,0 +1,73 @@
import React from "react";
import Emblem from "../Emblem";
import { FormattedMessage } from "react-intl";
import css from "../css/Config.css";
const Config = props => {
console.log(props.pattern);
const emblem = (t1, t2) =>
<Emblem text1={t1} text2={t2} color1="#61dafb" color2="#fff" size={20}/>
const renderConfig = () => {
let c = props.pattern.config;
let rows = [];
for (let key of ["name", "version"])
rows.push(<tr><td>
<span className={css.key}>{key}:</span>
<span className={css.val}>{c[key]}</span>
</td></tr>);
for (let key of ["measurements", "parts", "hide"]) {
let list = [];
if (typeof c[key] !== "undefined") {
for (let item of c[key]) list.push(<li><span className={css.val}>{item}</span></li>);
rows.push(<tr><td>
<span className={css.key}>{key}:</span>
<ul className={css.config}>{list}</ul>
</td></tr>);
} else rows.push(<tr><td><span className={css.key}>{key}:</span></td></tr>);
}
for (let key of ["dependencies", "inject"]) {
if (typeof c[key] !== "undefined") {
let list = [];
for (let item of Object.keys(c[key])) {
let values = null;
if (typeof c[key][item] === "string") {
list.push(<li>
<span className={css.subkey}>{item}
{ key === "inject" ? " «" : ":"}
</span>
<span className={css.val}>{c[key][item]}</span>
</li>);
} else if (c[key][item].length > 0) {
list.push(<li>
<span className={css.subkey}>{item}:</span>
<span className={css.val}>{c[key][item].map(v => v+" ")}</span>
</li>);
}
}
rows.push(<tr><td>
<span className={css.key}>{key}:</span>
<ul className={css.config}>{list}</ul>
</td></tr>);
} else rows.push(<tr><td><span className={css.key}>{key}:</span></td></tr>);
}
return (
<table className={css.config}>
<thead>
<tr><th>{emblem("config",".js")}</th></tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
);
}
return (
<div className={css.config}>
{renderConfig()}
</div>
);
}
export default Config;

View file

@ -0,0 +1,25 @@
import React from "react";
import Emblem from "../Emblem";
import { FormattedMessage } from "react-intl";
import css from "../css/Config.css";
const Measurements = props => {
const emblem = (t1, t2) =>
<Emblem text1={t1} text2={t2} color1="#61dafb" color2="#fff" size={20}/>
return (
<div className={css.config}>
<table className={css.config}>
<thead>
<tr><th><FormattedMessage id="app.measurements" /></th></tr>
</thead>
<tbody>
</tbody>
</table>
<pre>
{JSON.stringify(props, null, 2)}
</pre>
</div>
);
}
export default Measurements;

View file

@ -0,0 +1,106 @@
import React from "react";
import Emblem from "../Emblem";
import { FormattedMessage } from "react-intl";
import css from "../css/Config.css";
const Options = props => {
const emblem = (t1, t2) =>
<Emblem text1={t1} text2={t2} color1="#61dafb" color2="#fff" size={20}/>
const renderOptions = () => {
let c = props.pattern.config;
let rows = [];
if (typeof c.options !== "undefined") {
let list = [];
for (let item of Object.keys(c.options).sort()) {
let values = null;
if (typeof c.options[item] === "boolean") {
rows.push(<tr><td>
<span className={css.key}>{item}:</span>
<span className={css.true}>{c.options[item] ? "TRUE" : "FALSE"}</span>
</td></tr>);
} else if (typeof c.options[item] !== "object") {
rows.push(<tr><td>
<span className={css.key}>{item}:</span>
<span className={css.val}>{c.options[item]}</span>
</td></tr>);
} else {
if (typeof c.options[item].pct !== "undefined") {
rows.push(<tr><td>
<span className={css.key}>{item}:</span>
<span className={css.val}>
{c.options[item].min}%
{" / "}
<b>{c.options[item].pct}%</b>
{" / "}
{c.options[item].max}%
</span>
</td></tr>);
} else if (typeof c.options[item].deg !== "undefined") {
rows.push(<tr><td>
<span className={css.key}>{item}:</span>
<span className={css.val}>
{c.options[item].min}&deg;
{" / "}
<b>{c.options[item].deg}&deg;</b>
{" / "}
{c.options[item].max}&deg;
</span>
</td></tr>);
} else if (typeof c.options[item].mm !== "undefined") {
rows.push(<tr><td>
<span className={css.key}>{item}:</span>
<span className={css.val}>
{c.options[item].min}mm;
{" / "}
<b>{c.options[item].mm}mm</b>
{" / "}
{c.options[item].max}mm
</span>
</td></tr>);
} else if (typeof c.options[item].bool !== "undefined") {
rows.push(<tr><td>
<span className={css.key}>{item}:</span>
{c.options[item].bool
? <React.Fragment><span className={css.true}>TRUE</span><span> / FALSE</span></React.Fragment>
: <React.Fragment><span>TRUE / </span><span className={css.false}>FALSE</span></React.Fragment>
}
</td></tr>);
} else if (typeof c.options[item].list !== "undefined") {
let list = [];
for (let opt of c.options[item].list) {
if (opt === c.options[item].dflt) list.push(<li><b>{opt}</b> &laquo;</li>);
else list.push(<li>{opt}</li>);
}
rows.push(<tr><td>
<span className={css.key}>{item}:</span>
<ul className={css.config}>{list}</ul>
</td></tr>);
} else {
rows.push(<tr><td>
<span className={css.key}>{item}:</span>
<span className={css.val}>FIXME</span>
</td></tr>);
}
}
}
} else return null;
return (
<table className={css.config}>
<thead>
<tr><th>{emblem(c.name+".config",".options")}</th></tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
);
}
return (
<div className={css.config}>
{renderOptions()}
</div>
);
}
export default Options;

View file

@ -0,0 +1,65 @@
import React from "react";
import Emblem from "../Emblem";
import { FormattedMessage } from "react-intl";
import css from "../css/Config.css";
const ResolvedConfig = props => {
const emblem = (t1, t2) =>
<Emblem text1={t1} text2={t2} color1="#61dafb" color2="#fff" size={20}/>
const renderResolvedConfig = () => {
let c = props.pattern.config;
let rows = [];
let list = [];
if (typeof c.draftOrder !== "undefined") {
for (let item of c.draftOrder) list.push(<li><span className={css.val}>{item}</span></li>);
rows.push(<tr><td>
<span className={css.key}>draftOrder:</span>
<ol className={css.config}>{list}</ol>
</td></tr>);
} else rows.push(<tr><td><span className={css.key}>draftOrder:</span></td></tr>);
for (let key of ["resolvedDependencies"]) {
if (typeof c[key] !== "undefined") {
let list = [];
for (let item of Object.keys(c[key])) {
let values = null;
if (typeof c[key][item] === "string") {
list.push(<li>
<span className={css.subkey}>{item}
{ key === "inject" ? " «" : ":"}
</span>
<span className={css.val}>{c[key][item]}</span>
</li>);
} else if (c[key][item].length > 0) {
list.push(<li>
<span className={css.subkey}>{item}:</span>
<span className={css.val}>{c[key][item].map(v => v+" ")}</span>
</li>);
}
}
rows.push(<tr><td>
<span className={css.key}>{key}:</span>
<ul className={css.config}>{list}</ul>
</td></tr>);
} else rows.push(<tr><td><span className={css.key}>{key}:</span></td></tr>);
}
return (
<table className={css.config}>
<thead>
<tr><th>{emblem(c.name,".config")}</th></tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
);
}
return (
<div className={css.config}>
{renderResolvedConfig()}
</div>
);
}
export default ResolvedConfig;

View file

@ -0,0 +1,35 @@
import React from "react";
import Emblem from "../Emblem";
import { FormattedMessage } from "react-intl";
import css from "../css/Settings.css";
import Config from "./Config";
import ResolvedConfig from "./ResolvedConfig";
import Options from "./Options";
import Measurements from "./Measurements";
import Complete from "./options/draft-complete";
const Settings = props => {
let pattern = new props.freesewing.patterns[props.pattern]();
return (
<section>
<div className={css.wrapper}>
<Options pattern={pattern} />
<Measurements pattern={pattern} />
<div>
<Complete
pattern={props.pattern}
gist={{
complete: false
}}
updateGist={props.updateGist}
/>
</div>
</div>
</section>
);
}
//<Config pattern={pattern} />
//<ResolvedConfig pattern={pattern} />
export default Settings;

View file

@ -0,0 +1,44 @@
import React from "react";
import { FormattedMessage } from "react-intl";
import { strings } from "@freesewing/i18n";
const Complete = props => {
let complete, incomplete;
if (props.gist.complete) complete = "checked";
else incomplete = "checked";
return (
<div className="option draft">
<header>
<h5 className="do-title"><FormattedMessage id="settings.complete.title" /></h5>
<p className="do-description"><FormattedMessage id="settings.complete.description" /></p>
</header>
<ul className="radio">
<li>
<label>
<input
type="radio"
name="complete"
value={1}
onChange={evt => props.updateGist("complete", true)}
checked={props.gist.complete}
/>
<FormattedMessage id="app.yes" />
</label>
</li>
<li>
<label>
<input
type="radio"
name="complete"
value={0}
onChange={evt => props.updateGist("complete", false)}
checked={props.gist.complete}
/>
<FormattedMessage id="app.no" />
</label>
</li>
</ul>
</div>
);
}
export default Complete;

View file

@ -0,0 +1,155 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import storage from "./utils/storage"
import { i18n, strings } from "@freesewing/i18n";
import "./style.css";
import NavBar from "./components/NavBar";
import ButtonPicker from "./components/ButtonPicker";
import Settings from "./components/settings/";
import { IntlProvider, addLocaleData } from "react-intl";
import en from "react-intl/locale-data/en";
import de from "react-intl/locale-data/de";
import es from "react-intl/locale-data/es";
import fr from "react-intl/locale-data/fr";
import nl from "react-intl/locale-data/nl";
import createTheme from "@freesewing/mui-theme";
import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider';
import Button from "@material-ui/core/Button";
require("typeface-roboto-condensed");
require("@freesewing/css-theme");
addLocaleData([...en, ...de, ...es, ...fr, ...nl]);
export default class Workbench extends Component {
static propTypes = {
freesewing: PropTypes.object
}
constructor(props) {
super(props);
this.state = {
language: this.getLanguage(),
pattern: this.getPattern(),
settings: false,
gist: {},
theme: "light"
};
}
Storage = new storage();
saveToStorage = key => {
if (key === "language") this.Storage.set("language", this.state.language);
else if (key === "pattern") this.Storage.set("pattern", this.state.pattern);
else if (key === "gist") this.Storage.set(this.state.pattern, JSON.stringify(this.state.gist));
else {
this.Storage.set("language", this.state.language);
this.Storage.set("pattern", this.state.pattern);
this.Storage.set(this.state.pattern, JSON.stringify(this.state.gist));
}
}
getLanguage = () => {
let lang = this.Storage.get("language");
if (Object.keys(i18n).indexOf(lang) !== -1) return lang;
return false;
}
setLanguage = language => this.setState({ language }, () => this.saveToStorage('language'));
getPattern = () => {
let pattern = this.Storage.get("pattern");
if (Object.keys(this.props.freesewing.patterns).indexOf(pattern) !== -1) return pattern;
return false;
}
setPattern = pattern => this.setState({ pattern }, () => this.saveToStorage('pattern'));
getGist = () => {
let gist = this.Storage.get(JSON.parse(this.state.pattern));
if (typeof gist === "object") return gist;
return false;
}
setGist = gist => this.setState({ gist }, () => this.saveToStorage('gist'));
toggleSettings = () => {
let settings = !this.state.settings;
this.setState({ settings });
}
updateGist = (key, value) => {
if (key.substring(0, 7) === "options.") return updateOption(key.substring(7), value);
let gist = this.state.gist;
gist[key] = value;
this.setState({ gist }, () => this.saveToStorage('gist'));
}
toggleDarkmode = () => {
let theme = "light";
if (this.state.theme === "light") theme = "dark";
this.setState({ theme });
}
render() {
let main = null;
let navbar = null;
if (!this.state.language) {
navbar = <NavBar empty={true} />
let keys = Object.keys(i18n);
let values = {};
for (let lang of keys) values[lang] = i18n[lang][lang];
main = <ButtonPicker
setChoice={this.setLanguage}
keys={keys}
values={values}
/>
} else {
if (!this.state.pattern) {
navbar = <NavBar
clearLanguage={() => this.setLanguage(false)}
language={i18n[this.state.language][this.state.language]}
locale={this.state.language}
pattern={false}
/>
let keys = Object.keys(this.props.freesewing.patterns);
let values = {};
for (let pattern of keys) values[pattern] = pattern;
main = <ButtonPicker
setChoice={this.setPattern}
keys={keys}
values={values}
msgKey="app.chooseAPattern"
/>
} else {
navbar = <NavBar
clearLanguage={() => this.setLanguage(false)}
language={i18n[this.state.language][this.state.language]}
locale={this.state.language}
clearPattern={() => this.setPattern(false)}
pattern={this.state.pattern}
toggleSettings={this.toggleSettings}
/>
if (this.state.settings) main = <Settings
pattern={this.state.pattern}
gist={this.state.gist}
freesewing={this.props.freesewing}
updateGist={this.updateGist}
/>
else main = <div>Language is set<pre>{JSON.stringify(this.state, null, 2)}</pre></div>
}
}
return <IntlProvider
locale={this.state.language || 'en'}
messages={strings[this.state.language]}
>
<MuiThemeProvider theme={createTheme(true)}>
<React.Fragment>
{navbar}
<Button variant="contained" color="primary">test</Button>
{main}
</React.Fragment>
</MuiThemeProvider>
</IntlProvider>
}
}

View file

@ -0,0 +1,32 @@
body {
margin: 0;
padding: 0;
background: #fff;
font-feature-settings: "kern", "liga", "clig", "calt";
word-wrap: break-word;
font-kerning: normal;
font-family: -apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;
line-height: 1.4;
}
a {
color: #61dafb;
transition: color 0.2s ease-out;
text-decoration: none;
}
a:hover {
color: #f58fff;
}
button:hover {
cursor: pointer;
}
section {
width: 100%;
min-height: calc(100vh - 64px);
display: flex;
background: #222;
color: #fff;
}

View file

@ -0,0 +1,7 @@
import ExampleComponent from './'
describe('ExampleComponent', () => {
it('is truthy', () => {
expect(ExampleComponent).toBeTruthy()
})
})

View file

@ -0,0 +1,29 @@
export default class Storage {
set(key, value, isJson) {
if (typeof localStorage === "undefined") {
return;
}
const _key = "fswb_" + key;
if (typeof value === "undefined" || value === null) {
localStorage.removeItem(_key);
} else {
localStorage.setItem(_key, isJson ? JSON.stringify(value) : value);
}
return value;
}
get(key, isJson) {
if (typeof localStorage === "undefined") {
return;
}
const _key = "fswb_" + key;
const value = localStorage.getItem(_key);
return isJson ? JSON.parse(value) : value;
}
}