diff --git a/src/components/forms/buffered-input-hoc.jsx b/src/components/forms/buffered-input-hoc.jsx new file mode 100644 index 00000000..b3561136 --- /dev/null +++ b/src/components/forms/buffered-input-hoc.jsx @@ -0,0 +1,64 @@ +/* DO NOT EDIT +@todo This file is copied from GUI and should be pulled out into a shared library. +See https://github.com/LLK/scratch-paint/issues/13 */ + +import bindAll from 'lodash.bindall'; +import PropTypes from 'prop-types'; +import React from 'react'; + +/** + * Higher Order Component to manage inputs that submit on blur and + * @param {React.Component} Input text input that consumes onChange, onBlur, onKeyPress + * @returns {React.Component} Buffered input that calls onSubmit on blur and + */ +export default function (Input) { + class BufferedInput extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleChange', + 'handleKeyPress', + 'handleFlush' + ]); + this.state = { + value: null + }; + } + handleKeyPress (e) { + if (e.key === 'Enter') { + this.handleFlush(); + e.target.blur(); + } + } + handleFlush () { + const isNumeric = typeof this.props.value === 'number'; + const validatesNumeric = isNumeric ? !isNaN(this.state.value) : true; + if (this.state.value !== null && validatesNumeric) { + this.props.onSubmit(isNumeric ? Number(this.state.value) : this.state.value); + } + this.setState({value: null}); + } + handleChange (e) { + this.setState({value: e.target.value}); + } + render () { + const bufferedValue = this.state.value === null ? this.props.value : this.state.value; + return ( + + ); + } + } + + BufferedInput.propTypes = { + onSubmit: PropTypes.func.isRequired, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + }; + + return BufferedInput; +} diff --git a/src/components/forms/input.css b/src/components/forms/input.css new file mode 100644 index 00000000..36855e44 --- /dev/null +++ b/src/components/forms/input.css @@ -0,0 +1,46 @@ +/* DO NOT EDIT +@todo This file is copied from GUI and should be pulled out into a shared library. +See https://github.com/LLK/scratch-paint/issues/13 */ + +@import "../../css/units.css"; +@import "../../css/colors.css"; + +.input-form { + height: 2rem; + padding: 0 0.75rem; + + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 0.625rem; + font-weight: bold; + color: $text-primary; + + border-width: 1px; + border-style: solid; + border-color: $form-border; + border-radius: 2rem; + + outline: none; + cursor: text; + transition: 0.25s ease-out; /* @todo: standardize with var */ + box-shadow: none; + + /* + For truncating overflowing text gracefully + Min-width is for a bug: https://css-tricks.com/flexbox-truncated-text + @todo: move this out into a mixin or a helper component + */ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + min-width: 0; +} + +.input-form:focus { + border-color: #4c97ff; + box-shadow: inset 0 0 0 -2px rgba(0, 0, 0, 0.1); +} + +.input-small { + width: 3rem; + text-align: center; +} diff --git a/src/components/forms/input.jsx b/src/components/forms/input.jsx new file mode 100644 index 00000000..1c6d087a --- /dev/null +++ b/src/components/forms/input.jsx @@ -0,0 +1,31 @@ +/* DO NOT EDIT +@todo This file is copied from GUI and should be pulled out into a shared library. +See https://github.com/LLK/scratch-paint/issues/13 */ + +import PropTypes from 'prop-types'; +import React from 'react'; +import classNames from 'classnames'; + +import styles from './input.css'; + +const Input = props => { + const {small, ...componentProps} = props; + return ( + + ); +}; + +Input.propTypes = { + small: PropTypes.bool +}; + +Input.defaultProps = { + small: false +}; + +export default Input; diff --git a/src/components/forms/label.css b/src/components/forms/label.css new file mode 100644 index 00000000..7871cdd3 --- /dev/null +++ b/src/components/forms/label.css @@ -0,0 +1,23 @@ +/* DO NOT EDIT +@todo This file is copied from GUI and should be pulled out into a shared library. +See https://github.com/LLK/scratch-paint/issues/13 */ + +@import "../../css/units.css"; +@import "../../css/colors.css"; + +.input-group { + display: inline-flex; + flex-direction: row; + align-items: center; +} + +.input-label, .input-label-secondary { + font-size: 0.625rem; + margin-right: calc($space / 2); + user-select: none; + cursor: default; +} + +.input-label { + font-weight: bold; +} diff --git a/src/components/forms/label.jsx b/src/components/forms/label.jsx new file mode 100644 index 00000000..475ffb00 --- /dev/null +++ b/src/components/forms/label.jsx @@ -0,0 +1,29 @@ +/* DO NOT EDIT +@todo This file is copied from GUI and should be pulled out into a shared library. +See https://github.com/LLK/scratch-paint/issues/13 */ + +import PropTypes from 'prop-types'; +import React from 'react'; + +import styles from './label.css'; + +const Label = props => ( + +); + +Label.propTypes = { + children: PropTypes.node, + secondary: PropTypes.bool, + text: PropTypes.string.isRequired +}; + +Label.defaultProps = { + secondary: false +}; + +export default Label; diff --git a/src/components/paint-editor.css b/src/components/paint-editor.css new file mode 100644 index 00000000..71651430 --- /dev/null +++ b/src/components/paint-editor.css @@ -0,0 +1,88 @@ +@import "../css/colors.css"; +@import "../css/units.css"; + +.editor-container { + display: flex; + flex-direction: column; + padding: calc(2 * $space); +} + +.row { + display: flex; + flex-direction: row; + align-items: center; +} + +.top-align-row { + padding-top:20px; + display: flex; + flex-direction: row; +} + +.row + .row { + margin-top: calc(2 * $space); +} + +.input-group + .input-group { + margin-left: calc(2 * $space); +} + +$border-radius: 0.25rem; + +.button { + height: 2rem; + padding: 0.25rem; + outline: none; + background: white; + border-radius: $border-radius; + border: 1px solid #ddd; + cursor: pointer; + font-size: 0.85rem; + transition: 0.2s; +} + +.button > img { + flex-grow: 1; + max-width: 100%; + max-height: 100%; + min-width: 1.5rem; +} + +.button-group { + margin: 0 1rem; +} + +.button-group .button { + border-radius: 0; + border-left: none; +} + +.button-group .button:last-of-type { + border-top-right-radius: $border-radius; + border-bottom-right-radius: $border-radius; +} + +.button-group .button:first-of-type { + border-left: 1px solid #ddd; + border-top-left-radius: $border-radius; + border-bottom-left-radius: $border-radius; +} + +.button:disabled > img { + opacity: 0.25; +} + +.canvas-container { + width: 503px; + height: 403px; + background-color: #e8edf1; + border: 1px solid #e8edf1; + border-radius: 2px; + position: relative; + overflow: visible; +} + +.mode-selector { + display: flex; + flex-direction: column; +} diff --git a/src/components/paint-editor.jsx b/src/components/paint-editor.jsx index 306bde8f..4b482f5d 100644 --- a/src/components/paint-editor.jsx +++ b/src/components/paint-editor.jsx @@ -6,6 +6,32 @@ import EraserMode from '../containers/eraser-mode.jsx'; import PropTypes from 'prop-types'; import LineMode from '../containers/line-mode.jsx'; +import {defineMessages, injectIntl, intlShape} from 'react-intl'; +import BufferedInputHOC from './forms/buffered-input-hoc.jsx'; +import Label from './forms/label.jsx'; +import Input from './forms/input.jsx'; + +import styles from './paint-editor.css'; + +const BufferedInput = BufferedInputHOC(Input); +const messages = defineMessages({ + costume: { + id: 'paint.paintEditor.costume', + description: 'Label for the name of a sound', + defaultMessage: 'Costume' + }, + fill: { + id: 'paint.paintEditor.fill', + description: 'Label for the color picker for the fill color', + defaultMessage: 'Fill' + }, + outline: { + id: 'paint.paintEditor.outline', + description: 'Label for the color picker for the outline color', + defaultMessage: 'Outline' + } +}); + class PaintEditorComponent extends React.Component { constructor (props) { super(props); @@ -18,44 +44,134 @@ class PaintEditorComponent extends React.Component { this.setState({canvas: canvas}); } render () { - // Modes can't work without a canvas, so we don't render them until we have it - if (this.state.canvas) { - return ( -
- - - - -
- ); - } return ( -
- +
+ {/* First row */} +
+ {/* Name field */} +
+ +
+ + {/* Undo/Redo */} +
+
+ + +
+
+ + {/* To be Front/back */} +
+ + +
+ + {/* To be Group/Ungroup */} +
+ + +
+
+ + {/* Second Row */} +
+ {/* To be fill */} +
+ +
+ {/* To be stroke */} +
+ +
+ +
+ Mode tools +
+
+ +
+ {/* Modes */} + {this.state.canvas ? ( +
+ + + +
+ ) : null} + + {/* Canvas */} +
+ +
+
); } } PaintEditorComponent.propTypes = { + intl: intlShape, onUpdateSvg: PropTypes.func.isRequired, rotationCenterX: PropTypes.number, rotationCenterY: PropTypes.number, svg: PropTypes.string }; -export default PaintEditorComponent; +export default injectIntl(PaintEditorComponent); diff --git a/src/containers/paper-canvas.css b/src/containers/paper-canvas.css new file mode 100644 index 00000000..d2f149fa --- /dev/null +++ b/src/containers/paper-canvas.css @@ -0,0 +1,7 @@ +.paper-canvas { + width: 500px; + height: 400px; + margin: auto; + position: relative; + background-color: #fff; +} diff --git a/src/containers/paper-canvas.jsx b/src/containers/paper-canvas.jsx index fdd6e44d..50e95b51 100644 --- a/src/containers/paper-canvas.jsx +++ b/src/containers/paper-canvas.jsx @@ -3,6 +3,8 @@ import PropTypes from 'prop-types'; import React from 'react'; import paper from 'paper'; +import styles from './paper-canvas.css'; + class PaperCanvas extends React.Component { constructor (props) { super(props); @@ -60,7 +62,10 @@ class PaperCanvas extends React.Component { render () { return ( ); } diff --git a/src/css/colors.css b/src/css/colors.css new file mode 100644 index 00000000..0fe15fca --- /dev/null +++ b/src/css/colors.css @@ -0,0 +1,23 @@ +/* DO NOT EDIT +@todo This file is copied from GUI and should be pulled out into a shared library. +See https://github.com/LLK/scratch-paint/issues/13 */ + +$ui-pane-border: #D9D9D9; +$ui-pane-gray: #F9F9F9; +$ui-background-blue: #e8edf1; + +$text-primary: #575e75; + +$motion-primary: #4C97FF; +$motion-tertiary: #3373CC; +$motion-transparent: hsla(215, 100%, 65%, 0.20); + +$red-primary: #FF661A; +$red-tertiary: #E64D00; + +$sound-primary: #CF63CF; +$sound-tertiary: #A63FA6; + +$control-primary: #FFAB19; + +$form-border: #E9EEF2; diff --git a/src/css/units.css b/src/css/units.css new file mode 100644 index 00000000..acb466b1 --- /dev/null +++ b/src/css/units.css @@ -0,0 +1,15 @@ +/* DO NOT EDIT +@todo This file is copied from GUI and should be pulled out into a shared library. +See https://github.com/LLK/scratch-paint/issues/13 */ + +$space: 0.5rem; + +$sprites-per-row: 5; + +$menu-bar-height: 3rem; +$sprite-info-height: 6rem; +$stage-menu-height: 2.75rem; + +$library-header-height: 4.375rem; + +$form-radius: calc($space / 2);