diff --git a/src/components/close-button/close-button.css b/src/components/close-button/close-button.css new file mode 100644 index 0000000000000000000000000000000000000000..ef48624c4c69a1d2a3d96d263a3eeaa44bdf65f2 --- /dev/null +++ b/src/components/close-button/close-button.css @@ -0,0 +1,44 @@ +@import "../../css/colors.css"; +@import "../../css/units.css"; + +.close-button { + display: flex; + align-items: center; + justify-content: center; + + color: gray; + background-color: $blue; + + border-radius: 50%; + border-color: #dbdbdb; + border-style: solid; + + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + cursor: pointer; + transition: all 0.15s ease-out; /* @todo: standardize with var */ +} + +.small { + width: 1rem; + height: 1rem; + border-width: 1px; +} + +.large { + width: 2.75rem; + height: 2.75rem; + border-width: 2px; +} + +.close-button:hover { + transform: scale(1.1, 1.1); +} + +/* Same icon as Sprite Selector Add button, but rotated. + TODO: reuse? +*/ +.close-icon { + transform-origin: 50%; + transform: rotate(45deg); + width: 40%; +} diff --git a/src/components/close-button/close-button.jsx b/src/components/close-button/close-button.jsx new file mode 100644 index 0000000000000000000000000000000000000000..a72656e6e1db02ccdc53db62cd140b447e8c0cee --- /dev/null +++ b/src/components/close-button/close-button.jsx @@ -0,0 +1,39 @@ +const React = require('react'); +const classNames = require('classnames'); + +const styles = require('./close-button.css'); +const closeIcon = require('./icon--close.svg'); + +const CloseButton = props => ( + <div + className={classNames( + styles.closeButton, + props.className, + { + [styles.large]: props.size === CloseButton.SIZE_LARGE, + [styles.small]: props.size === CloseButton.SIZE_SMALL + } + )} + onClick={props.onClick} + > + <img + className={styles.closeIcon} + src={closeIcon} + /> + </div> +); + +CloseButton.SIZE_LARGE = 'large'; +CloseButton.SIZE_SMALL = 'small'; + +CloseButton.propTypes = { + className: React.PropTypes.string, + onClick: React.PropTypes.func, + size: React.PropTypes.oneOf([CloseButton.SIZE_LARGE, CloseButton.SIZE_SMALL]) +}; + +CloseButton.defaultProps = { + size: CloseButton.SIZE_LARGE +}; + +module.exports = CloseButton; diff --git a/src/components/modal/icon--close.svg b/src/components/close-button/icon--close.svg similarity index 100% rename from src/components/modal/icon--close.svg rename to src/components/close-button/icon--close.svg diff --git a/src/components/modal/modal.css b/src/components/modal/modal.css index 46a51a19111398728c0196fa48f90527b11460e5..dea04e1f428504b8cedeb8d9d24cec9c2e964b14 100644 --- a/src/components/modal/modal.css +++ b/src/components/modal/modal.css @@ -33,38 +33,9 @@ background: $ui-pane-gray; } -.modal-close-button { - display: flex; +.close-button { position: absolute; - z-index: 2147483647; - align-items: center; - justify-content: center; - top: 1rem; right: 1rem; - width: 2.75rem !important; - height: 2.75rem !important; - - color: gray; - background-color: $blue; - - border-radius: 50% !important; - border: 2px solid #dbdbdb; - - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - cursor: pointer; - transition: all 0.15s ease-out; /* @todo: standardize with var */ -} - -.modal-close-button:hover { - transform: scale(1.1, 1.1); -} - -/* Same icon as Sprite Selector Add button, but rotated. - @todo: reuse? -*/ -.close-icon { - transform-origin: 50%; - transform: rotate(45deg); - width: 40%; + z-index: 2; } diff --git a/src/components/modal/modal.jsx b/src/components/modal/modal.jsx index 51c5e353daa73cf83c820e2df64b7475fb59cc68..17537a8922616a8a223d007ac7851c4e14d10e29 100644 --- a/src/components/modal/modal.jsx +++ b/src/components/modal/modal.jsx @@ -2,9 +2,9 @@ const React = require('react'); const ReactModal = require('react-modal'); const Box = require('../box/box.jsx'); +const CloseButton = require('../close-button/close-button.jsx'); const styles = require('./modal.css'); -const closeIcon = require('./icon--close.svg'); class ModalComponent extends React.Component { render () { @@ -17,15 +17,10 @@ class ModalComponent extends React.Component { ref={m => (this.modal = m)} onRequestClose={this.props.onRequestClose} > - <div - className={styles.modalCloseButton} + <CloseButton + className={styles.closeButton} onClick={this.props.onRequestClose} - > - <img - className={styles.closeIcon} - src={closeIcon} - /> - </div> + /> <Box className={styles.modalChildren} direction="column" diff --git a/src/components/sprite-selector-item/sprite-selector-item.css b/src/components/sprite-selector-item/sprite-selector-item.css index f3a3655122e9aa806c505c4aecd78bdf0dbef73d..787be776b4f17581841adf9d641b873e6009edbf 100644 --- a/src/components/sprite-selector-item/sprite-selector-item.css +++ b/src/components/sprite-selector-item/sprite-selector-item.css @@ -5,6 +5,8 @@ display: flex; flex-direction: column; justify-content: flex-start; + position: relative; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 0.8rem; background: white; @@ -30,7 +32,7 @@ transition: 0.25s ease-out; } .sprite-selector-item.is-selected .info-button { - display: block; + display: block; } .sprite-image { @@ -40,12 +42,19 @@ .sprite-name { font-size: 0.625rem; margin: 0.15rem; - /* + /* For truncating overflowing text gracefully Min-width is for a bug: https://css-tricks.com/flexbox-truncated-text */ - overflow: hidden; + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; } + +.delete-button { + position: absolute; + top: 0.125rem; + right: 0.125rem; + z-index: 2; +} diff --git a/src/components/sprite-selector-item/sprite-selector-item.jsx b/src/components/sprite-selector-item/sprite-selector-item.jsx index 549faedf6f7fa647283d9960d2d1eac7fa56b947..13f7ebcea9a6173933af8e3b7e61d33d987612d4 100644 --- a/src/components/sprite-selector-item/sprite-selector-item.jsx +++ b/src/components/sprite-selector-item/sprite-selector-item.jsx @@ -3,6 +3,7 @@ const React = require('react'); const Box = require('../box/box.jsx'); const CostumeCanvas = require('../costume-canvas/costume-canvas.jsx'); +const CloseButton = require('../close-button/close-button.jsx'); const styles = require('./sprite-selector-item.css'); const SpriteSelectorItem = props => ( @@ -16,6 +17,13 @@ const SpriteSelectorItem = props => ( )} onClick={props.onClick} > + {props.selected ? ( + <CloseButton + className={styles.deleteButton} + size={CloseButton.SIZE_SMALL} + onClick={props.onDeleteButtonClick} + /> + ) : null } {props.costumeURL ? ( <CostumeCanvas className={styles.spriteImage} @@ -33,6 +41,7 @@ SpriteSelectorItem.propTypes = { costumeURL: React.PropTypes.string, name: React.PropTypes.string, onClick: React.PropTypes.func, + onDeleteButtonClick: React.PropTypes.func, selected: React.PropTypes.bool }; diff --git a/src/components/sprite-selector/sprite-selector.jsx b/src/components/sprite-selector/sprite-selector.jsx index e33ccaf29de3396f5d87ad5c012667fbf1d1f821..8d8ff9ca370bf980c171f5e626f2fbfb35a49970 100644 --- a/src/components/sprite-selector/sprite-selector.jsx +++ b/src/components/sprite-selector/sprite-selector.jsx @@ -13,6 +13,7 @@ const SpriteSelectorComponent = function (props) { onChangeSpriteVisibility, onChangeSpriteX, onChangeSpriteY, + onDeleteSprite, onSelectSprite, selectedId, sprites, @@ -59,6 +60,7 @@ const SpriteSelectorComponent = function (props) { name={sprites[id].name} selected={id === selectedId} onClick={onSelectSprite} + onDeleteButtonClick={onDeleteSprite} /> )) } @@ -75,6 +77,7 @@ SpriteSelectorComponent.propTypes = { onChangeSpriteVisibility: React.PropTypes.func, onChangeSpriteX: React.PropTypes.func, onChangeSpriteY: React.PropTypes.func, + onDeleteSprite: React.PropTypes.func, onSelectSprite: React.PropTypes.func, selectedId: React.PropTypes.string, sprites: React.PropTypes.shape({ diff --git a/src/components/target-pane/target-pane.jsx b/src/components/target-pane/target-pane.jsx index c918b034e85dde327b774f3a8528bc18267a1033..29bb8c7d46d7c3e731bbc7a8bd6fc936343022e6 100644 --- a/src/components/target-pane/target-pane.jsx +++ b/src/components/target-pane/target-pane.jsx @@ -43,6 +43,7 @@ class TargetPane extends React.Component { onChangeSpriteVisibility, onChangeSpriteX, onChangeSpriteY, + onDeleteSprite, onNewSpriteClick, onNewBackdropClick, onRequestCloseBackdropLibrary, @@ -69,6 +70,7 @@ class TargetPane extends React.Component { onChangeSpriteVisibility={onChangeSpriteVisibility} onChangeSpriteX={onChangeSpriteX} onChangeSpriteY={onChangeSpriteY} + onDeleteSprite={onDeleteSprite} onSelectSprite={onSelectSprite} /> <Box className={styles.stageSelectorWrapper}> @@ -150,6 +152,7 @@ TargetPane.propTypes = { onChangeSpriteVisibility: React.PropTypes.func, onChangeSpriteX: React.PropTypes.func, onChangeSpriteY: React.PropTypes.func, + onDeleteSprite: React.PropTypes.func, onNewBackdropClick: React.PropTypes.func, onNewSpriteClick: React.PropTypes.func, onRequestCloseBackdropLibrary: React.PropTypes.func, diff --git a/src/containers/sprite-selector-item.jsx b/src/containers/sprite-selector-item.jsx index 9ea66dcf3c8650bf059dddcc54266ce837756ba5..a9e538f30d4f11a3d134d3ef6348dc4ed9f2b554 100644 --- a/src/containers/sprite-selector-item.jsx +++ b/src/containers/sprite-selector-item.jsx @@ -7,22 +7,31 @@ class SpriteSelectorItem extends React.Component { constructor (props) { super(props); bindAll(this, [ - 'handleClick' + 'handleClick', + 'handleDelete' ]); } handleClick (e) { e.preventDefault(); this.props.onClick(this.props.id); } + handleDelete () { + // eslint-disable-next-line no-alert + if (window.confirm('Are you sure you want to delete this sprite?')) { + this.props.onDeleteButtonClick(this.props.id); + } + } render () { const { id, // eslint-disable-line no-unused-vars onClick, // eslint-disable-line no-unused-vars + onDeleteButtonClick, // eslint-disable-line no-unused-vars ...props } = this.props; return ( <SpriteSelectorItemComponent onClick={this.handleClick} + onDeleteButtonClick={this.handleDelete} {...props} /> ); @@ -34,6 +43,7 @@ SpriteSelectorItem.propTypes = { id: React.PropTypes.string, name: React.PropTypes.string, onClick: React.PropTypes.func, + onDeleteButtonClick: React.PropTypes.func, selected: React.PropTypes.bool }; diff --git a/src/containers/target-pane.jsx b/src/containers/target-pane.jsx index 45033a72f921694de506834227caa532ee4a7c60..4afcfed2ceb55fcf22766a57bb93cea45c47e01d 100644 --- a/src/containers/target-pane.jsx +++ b/src/containers/target-pane.jsx @@ -23,6 +23,7 @@ class TargetPane extends React.Component { 'handleChangeSpriteVisibility', 'handleChangeSpriteX', 'handleChangeSpriteY', + 'handleDeleteSprite', 'handleSelectSprite' ]); } @@ -44,6 +45,9 @@ class TargetPane extends React.Component { handleChangeSpriteY (y) { this.props.vm.postSpriteInfo({y}); } + handleDeleteSprite (id) { + this.props.vm.deleteSprite(id); + } handleSelectSprite (id) { this.props.vm.setEditingTarget(id); } @@ -57,6 +61,7 @@ class TargetPane extends React.Component { onChangeSpriteVisibility={this.handleChangeSpriteVisibility} onChangeSpriteX={this.handleChangeSpriteX} onChangeSpriteY={this.handleChangeSpriteY} + onDeleteSprite={this.handleDeleteSprite} onSelectSprite={this.handleSelectSprite} /> );