diff --git a/packages/freesewing.shared/components/workbench/draft/circle/index.js b/packages/freesewing.shared/components/workbench/draft/circle/index.js new file mode 100644 index 00000000000..72dedf1bf14 --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/circle/index.js @@ -0,0 +1,10 @@ +const Circle = (props) => ( + +) + +export default Circle diff --git a/packages/freesewing.shared/components/workbench/draft/defs/index.js b/packages/freesewing.shared/components/workbench/draft/defs/index.js new file mode 100644 index 00000000000..4f494dee70a --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/defs/index.js @@ -0,0 +1,69 @@ +const style = ` style="fill: none; stroke: currentColor;" ` +const grids = { + imperial: ` + + + + + + + `, + metric: ` + + + + + + + + + ` +} + +const Defs = (props) => { + let defs = props.svg.defs + if (props.settings.paperless) { + defs += grids[props.settings.units || 'metric'] + for (let p in props.parts) { + let anchor = { x: 0, y: 0 } + if (typeof props.parts[p].points.gridAnchor !== 'undefined') + anchor = props.parts[p].points.gridAnchor + else if (typeof props.parts[p].points.anchor !== 'undefined') + anchor = props.parts[p].points.anchor + + defs += `` + } + } + + return +} + +export default Defs diff --git a/packages/freesewing.shared/components/workbench/draft/index.js b/packages/freesewing.shared/components/workbench/draft/index.js new file mode 100644 index 00000000000..7d41c1bbe27 --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/index.js @@ -0,0 +1,35 @@ +import React, { useState } from 'react' +import Svg from './svg' +import Defs from './defs' +import Part from './part' + +const LabDraft = ({ app, pattern, gist, updateGist }) => { + + const patternInstance = new pattern(gist) + patternInstance.draft() + const patternProps = patternInstance.getRenderProps() + + + + return ( + + + + + {Object.keys(patternProps.parts).map((name) => ( + + ))} + + + ) +} + +export default LabDraft diff --git a/packages/freesewing.shared/components/workbench/draft/part/index.js b/packages/freesewing.shared/components/workbench/draft/part/index.js new file mode 100644 index 00000000000..daa51335935 --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/part/index.js @@ -0,0 +1,139 @@ +import Path from '../path' +import Point from '../point' +import Snippet from '../snippet' +import { getProps } from '../utils' + +const Part = (props) => { + const focusPoint = (point, i) => { + const p = props.part.points[point] + const pathString = `M ${p.x} ${props.part.topLeft.y} ` + + `L ${p.x} ${props.part.bottomRight.y} ` + + `M ${props.part.topLeft.x} ${p.y} ` + + `L ${props.part.bottomRight.x} ${p.y} ` + const classes = 'focus point c' + (i % 8) // Cycle through 8 colors + return ( + + + + props.raiseEvent('clearFocus', { + part: props.name, + type: 'points', + name: point + }) + } + /> + + ) + } + + const focusCoords = (p, i) => { + let pathString = `M ${p.x} ${props.part.topLeft.y} ` + pathString += `L ${p.x} ${props.part.bottomRight.y} ` + pathString += `M ${props.part.topLeft.x} ${p.y} ` + pathString += `L ${props.part.bottomRight.x} ${p.y} ` + let classes = 'focus coords c' + (i % 4) // Cycle through 4 CSS classes + return ( + + + + props.raiseEvent('clearFocus', { + part: props.name, + type: 'coords', + data: p + }) + } + /> + + ) + } + + let grid = props.paperless ? ( + + ) : null + + let focus = [] + if (props.develop) { + if (props.focus && typeof props.focus[props.name] !== 'undefined') { + for (let i in props.focus[props.name].points) + focus.push(focusPoint(props.focus[props.name].points[i], i)) + for (let i in props.focus[props.name].paths) { + let name = props.focus[props.name].paths[i] + focus.push( + + props.raiseEvent('clearFocus', { + part: props.name, + type: 'paths', + name + }) + } + /> + ) + } + for (let i in props.focus[props.name].coords) + focus.push(focusCoords(props.focus[props.name].coords[i], i)) + } + } + + return ( + + {grid} + {Object.keys(props.part.paths).map((name) => ( + + ))} + {Object.keys(props.part.points).map((name) => ( + + ))} + {Object.keys(props.part.snippets).map((name) => ( + + ))} + {focus} + + ) +} + +export default Part diff --git a/packages/freesewing.shared/components/workbench/draft/path/index.js b/packages/freesewing.shared/components/workbench/draft/path/index.js new file mode 100644 index 00000000000..2a1f6f33258 --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/path/index.js @@ -0,0 +1,17 @@ +import TextOnPath from '../text-on-path' +import { getProps } from '../utils' + +const Path = (props) => { + if (!props.path.render) return null + const output = [] + const pathId = 'path-' + props.part + '-' + props.name + output.push( + + ) + if (props.path.attributes.get('data-text')) + output.push() + + return output +} + +export default Path diff --git a/packages/freesewing.shared/components/workbench/draft/point/index.js b/packages/freesewing.shared/components/workbench/draft/point/index.js new file mode 100644 index 00000000000..88e5a290460 --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/point/index.js @@ -0,0 +1,14 @@ +import Text from '../text' +import Circle from '../circle' + +const Point = (props) => { + const output = [] + if (props.point.attributes && props.point.attributes.get('data-text')) + output.push() + if (props.point.attributes && props.point.attributes.get('data-circle')) + output.push() + + return output.length < 1 ? null : output +} + +export default Point diff --git a/packages/freesewing.shared/components/workbench/draft/snippet/index.js b/packages/freesewing.shared/components/workbench/draft/snippet/index.js new file mode 100644 index 00000000000..1d1fd0b1627 --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/snippet/index.js @@ -0,0 +1,27 @@ +import React from 'react' +import { getProps } from '../utils' + +const Snippet = (props) => { + const snippetProps = { + xlinkHref: '#' + props.snippet.def, + x: props.snippet.anchor.x, + y: props.snippet.anchor.y + } + let scale = props.snippet.attributes.get('data-scale') + let rotate = props.snippet.attributes.get('data-rotate') + if (scale || rotate) { + snippetProps.transform = '' + if (scale) { + snippetProps.transform += `translate(${snippetProps.x}, ${snippetProps.y}) ` + snippetProps.transform += `scale(${scale}) ` + snippetProps.transform += `translate(${snippetProps.x * -1}, ${snippetProps.y * -1}) ` + } + if (rotate) { + snippetProps.transform += `rotate(${rotate}, ${snippetProps.x}, ${snippetProps.y}) ` + } + } + + return +} + +export default Snippet diff --git a/packages/freesewing.shared/components/workbench/draft/svg/index.js b/packages/freesewing.shared/components/workbench/draft/svg/index.js new file mode 100644 index 00000000000..d9c629ea42a --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/svg/index.js @@ -0,0 +1,33 @@ +import React from 'react' + +const Svg = ({ + embed = true, + develop = false, + language = 'en', + className = 'freesewing pattern', + style = {}, + viewBox = false, + width, + height, + children +}) => { + let attributes = { + xmlns: 'http://www.w3.org/2000/svg', + 'xmlns:svg': 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + xmlLang: language, + viewBox: viewBox || `0 0 ${width} ${height}`, + className, + style + } + + if (!embed) { + attributes.width = width + 'mm' + attributes.height = height + 'mm' + } + if (develop) attributes.className += ' develop' + + return {children} +} + +export default Svg diff --git a/packages/freesewing.shared/components/workbench/draft/text-on-path/index.js b/packages/freesewing.shared/components/workbench/draft/text-on-path/index.js new file mode 100644 index 00000000000..1228d6fca51 --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/text-on-path/index.js @@ -0,0 +1,25 @@ +const TextOnPath = (props) => { + const text = [] + // Handle translation + let translated = '' + for (let string of props.path.attributes.getAsArray('data-text')) { + translated += props.app.t(string).replace(/"/g, '"') + ' ' + } + const textPathProps = { + xlinkHref: '#' + props.pathId, + startOffset: '0%' + } + const align = props.path.attributes.get('data-text-class') + if (align && align.indexOf('center') > -1) textPathProps.startOffset = '50%' + else if (align && align.indexOf('right') > -1) textPathProps.startOffset = '100%' + + return ( + + + {translated} + + + ) +} + +export default TextOnPath diff --git a/packages/freesewing.shared/components/workbench/draft/text/index.js b/packages/freesewing.shared/components/workbench/draft/text/index.js new file mode 100644 index 00000000000..05655c43057 --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/text/index.js @@ -0,0 +1,38 @@ +const Text = (props) => { + let text = [] + // Handle translation + let translated = '' + for (let string of props.point.attributes.getAsArray('data-text')) { + translated += props.app.t(string.toString()).replace(/"/g, '"') + ' ' + } + // Handle muti-line text + if (translated.indexOf('\n') !== -1) { + let key = 0 + let lines = translated.split('\n') + text.push({lines.shift()}) + for (let line of lines) { + key++ + text.push( + + {line.toString().replace(/"/g, '"')} + + ) + } + } else text.push({translated}) + + return ( + + {text} + + ) +} + +export default Text diff --git a/packages/freesewing.shared/components/workbench/draft/utils.js b/packages/freesewing.shared/components/workbench/draft/utils.js new file mode 100644 index 00000000000..f023e26b58b --- /dev/null +++ b/packages/freesewing.shared/components/workbench/draft/utils.js @@ -0,0 +1,36 @@ +export const getProps = (obj) => { + /** I can't believe it but there seems to be no method on NPM todo this */ + const cssKey = (key) => { + let chunks = key.split('-') + if (chunks.length > 1) { + key = chunks.shift() + for (let s of chunks) key += s.charAt(0).toUpperCase() + s.slice(1) + } + + return key + } + + const convert = (css) => { + let style = {} + let rules = css.split(';') + for (let rule of rules) { + let chunks = rule.split(':') + if (chunks.length === 2) style[cssKey(chunks[0].trim())] = chunks[1].trim() + } + return style + } + + let rename = { + class: 'className', + 'marker-start': 'markerStart', + 'marker-end': 'markerEnd' + } + let props = {} + for (let key in obj.attributes.list) { + if (key === 'style') props[key] = convert(obj.attributes.get(key)) + if (Object.keys(rename).indexOf(key) !== -1) props[rename[key]] = obj.attributes.get(key) + else if (key !== 'style') props[key] = obj.attributes.get(key) + } + + return props +}