Add very simple end animation
This commit is contained in:
1 parent
97d6308aa5
commit
4aa3b20a93
9 files changed
+135
-77
No files matched your search
@@ -112,3 +112,34 @@
|
||||
75% {transform: rotate(-2deg) scale(1.05);}
|
||||
100% {transform: rotate(0deg) scale(1.05);}
|
||||
}
|
||||
|
||||
.receivedBlocks {
|
||||
-webkit-animation: glowing 250ms;
|
||||
-moz-animation: glowing 250ms;
|
||||
-o-animation: glowing 250ms;
|
||||
animation: glowing 250ms;
|
||||
}
|
||||
|
||||
@-webkit-keyframes glowing {
|
||||
10% { -webkit-box-shadow: 0 0 10px #7fff1e; }
|
||||
90% { -webkit-box-shadow: 0 0 10px #7fff1e; }
|
||||
100% { -webkit-box-shadow: none; }
|
||||
}
|
||||
|
||||
@-moz-keyframes glowing {
|
||||
10% { -moz-box-shadow: 0 0 10px #7fff1e; }
|
||||
90% { -moz-box-shadow: 0 0 10px #7fff1e; }
|
||||
100% { -moz-box-shadow: none; }
|
||||
}
|
||||
|
||||
@-o-keyframes glowing {
|
||||
10% { box-shadow: 0 0 10px #7fff1e; }
|
||||
90% { box-shadow: 0 0 10px #7fff1e; }
|
||||
100% { box-shadow: none; }
|
||||
}
|
||||
|
||||
@keyframes glowing {
|
||||
10% { box-shadow: 0 0 10px #7fff1e; }
|
||||
90% { box-shadow: 0 0 10px #7fff1e; }
|
||||
100% { box-shadow: none; }
|
||||
}
|
||||
@@ -21,6 +21,8 @@ const messages = defineMessages({
|
||||
|
||||
const SpriteSelectorComponent = function (props) {
|
||||
const {
|
||||
editingTarget,
|
||||
hoveredTarget,
|
||||
intl,
|
||||
onChangeSpriteDirection,
|
||||
onChangeSpriteName,
|
||||
@@ -30,8 +32,6 @@ const SpriteSelectorComponent = function (props) {
|
||||
onChangeSpriteY,
|
||||
onDeleteSprite,
|
||||
onDuplicateSprite,
|
||||
onMouseOutSprite,
|
||||
onMouseOverSprite,
|
||||
onNewSpriteClick,
|
||||
onSelectSprite,
|
||||
raised,
|
||||
@@ -76,10 +76,12 @@ const SpriteSelectorComponent = function (props) {
|
||||
.map(sprite => (
|
||||
<SpriteSelectorItem
|
||||
assetId={sprite.costume && sprite.costume.assetId}
|
||||
className={
|
||||
(raised && sprite.id !== selectedId) ?
|
||||
classNames(styles.sprite, styles.raised) : styles.sprite
|
||||
}
|
||||
className={hoveredTarget.sprite === sprite.id &&
|
||||
sprite.id !== editingTarget &&
|
||||
hoveredTarget.receivedBlocks ?
|
||||
classNames(styles.sprite, styles.receivedBlocks) :
|
||||
raised && sprite.id !== editingTarget ?
|
||||
classNames(styles.sprite, styles.raised) : styles.sprite}
|
||||
id={sprite.id}
|
||||
key={sprite.id}
|
||||
name={sprite.name}
|
||||
@@ -87,8 +89,6 @@ const SpriteSelectorComponent = function (props) {
|
||||
onClick={onSelectSprite}
|
||||
onDeleteButtonClick={onDeleteSprite}
|
||||
onDuplicateButtonClick={onDuplicateSprite}
|
||||
onMouseOut={onMouseOutSprite}
|
||||
onMouseOver={onMouseOverSprite}
|
||||
/>
|
||||
))
|
||||
}
|
||||
@@ -105,6 +105,11 @@ const SpriteSelectorComponent = function (props) {
|
||||
};
|
||||
|
||||
SpriteSelectorComponent.propTypes = {
|
||||
editingTarget: PropTypes.string,
|
||||
hoveredTarget: PropTypes.shape({
|
||||
hoveredSprite: PropTypes.string,
|
||||
receivedBlocks: PropTypes.bool
|
||||
}),
|
||||
intl: intlShape.isRequired,
|
||||
onChangeSpriteDirection: PropTypes.func,
|
||||
onChangeSpriteName: PropTypes.func,
|
||||
@@ -114,8 +119,6 @@ SpriteSelectorComponent.propTypes = {
|
||||
onChangeSpriteY: PropTypes.func,
|
||||
onDeleteSprite: PropTypes.func,
|
||||
onDuplicateSprite: PropTypes.func,
|
||||
onMouseOutSprite: PropTypes.func,
|
||||
onMouseOverSprite: PropTypes.func,
|
||||
onNewSpriteClick: PropTypes.func,
|
||||
onSelectSprite: PropTypes.func,
|
||||
raised: PropTypes.bool,
|
||||
|
||||
@@ -19,6 +19,7 @@ import styles from './target-pane.css';
|
||||
const TargetPane = ({
|
||||
backdropLibraryVisible,
|
||||
editingTarget,
|
||||
hoveredTarget,
|
||||
spriteLibraryVisible,
|
||||
onChangeSpriteDirection,
|
||||
onChangeSpriteName,
|
||||
@@ -28,8 +29,6 @@ const TargetPane = ({
|
||||
onChangeSpriteY,
|
||||
onDeleteSprite,
|
||||
onDuplicateSprite,
|
||||
onMouseOutSprite,
|
||||
onMouseOverSprite,
|
||||
onNewSpriteClick,
|
||||
onRequestCloseSpriteLibrary,
|
||||
onRequestCloseBackdropLibrary,
|
||||
@@ -46,6 +45,8 @@ const TargetPane = ({
|
||||
>
|
||||
|
||||
<SpriteSelectorComponent
|
||||
editingTarget={editingTarget}
|
||||
hoveredTarget={hoveredTarget}
|
||||
raised={raiseSprites}
|
||||
selectedId={editingTarget}
|
||||
sprites={sprites}
|
||||
@@ -57,8 +58,6 @@ const TargetPane = ({
|
||||
onChangeSpriteY={onChangeSpriteY}
|
||||
onDeleteSprite={onDeleteSprite}
|
||||
onDuplicateSprite={onDuplicateSprite}
|
||||
onMouseOutSprite={onMouseOutSprite}
|
||||
onMouseOverSprite={onMouseOverSprite}
|
||||
onNewSpriteClick={onNewSpriteClick}
|
||||
onSelectSprite={onSelectSprite}
|
||||
/>
|
||||
@@ -113,6 +112,10 @@ TargetPane.propTypes = {
|
||||
backdropLibraryVisible: PropTypes.bool,
|
||||
editingTarget: PropTypes.string,
|
||||
extensionLibraryVisible: PropTypes.bool,
|
||||
hoveredTarget: PropTypes.shape({
|
||||
hoveredSprite: PropTypes.string,
|
||||
receivedBlocks: PropTypes.bool
|
||||
}),
|
||||
onChangeSpriteDirection: PropTypes.func,
|
||||
onChangeSpriteName: PropTypes.func,
|
||||
onChangeSpriteSize: PropTypes.func,
|
||||
@@ -121,8 +124,6 @@ TargetPane.propTypes = {
|
||||
onChangeSpriteY: PropTypes.func,
|
||||
onDeleteSprite: PropTypes.func,
|
||||
onDuplicateSprite: PropTypes.func,
|
||||
onMouseOutSprite: PropTypes.func,
|
||||
onMouseOverSprite: PropTypes.func,
|
||||
onNewSpriteClick: PropTypes.func,
|
||||
onRequestCloseBackdropLibrary: PropTypes.func,
|
||||
onRequestCloseExtensionLibrary: PropTypes.func,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import bindAll from 'lodash.bindall';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {setHoveredSprite} from '../reducers/hovered-target';
|
||||
|
||||
import SpriteSelectorItemComponent from '../components/sprite-selector-item/sprite-selector-item.jsx';
|
||||
|
||||
class SpriteSelectorItem extends React.Component {
|
||||
@@ -33,10 +34,10 @@ class SpriteSelectorItem extends React.Component {
|
||||
this.props.onDuplicateButtonClick(this.props.id);
|
||||
}
|
||||
handleMouseOut () {
|
||||
this.props.onMouseOut(this.props.id);
|
||||
this.props.dispatchSetHoveredSprite(null);
|
||||
}
|
||||
handleMouseOver () {
|
||||
this.props.onMouseOver(this.props.id);
|
||||
this.props.dispatchSetHoveredSprite(this.props.id);
|
||||
}
|
||||
render () {
|
||||
const {
|
||||
@@ -46,8 +47,7 @@ class SpriteSelectorItem extends React.Component {
|
||||
onClick,
|
||||
onDeleteButtonClick,
|
||||
onDuplicateButtonClick,
|
||||
onMouseOut,
|
||||
onMouseOver,
|
||||
receivedBlocks,
|
||||
/* eslint-enable no-unused-vars */
|
||||
...props
|
||||
} = this.props;
|
||||
@@ -56,8 +56,8 @@ class SpriteSelectorItem extends React.Component {
|
||||
onClick={this.handleClick}
|
||||
onDeleteButtonClick={onDeleteButtonClick ? this.handleDelete : null}
|
||||
onDuplicateButtonClick={onDuplicateButtonClick ? this.handleDuplicate : null}
|
||||
onMouseOut={onMouseOut ? this.handleMouseOut : null}
|
||||
onMouseOver={onMouseOver ? this.handleMouseOver : null}
|
||||
onMouseOut={this.handleMouseOut}
|
||||
onMouseOver={this.handleMouseOver}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@@ -67,20 +67,28 @@ class SpriteSelectorItem extends React.Component {
|
||||
SpriteSelectorItem.propTypes = {
|
||||
assetId: PropTypes.string,
|
||||
costumeURL: PropTypes.string,
|
||||
dispatchSetHoveredSprite: PropTypes.func.isRequired,
|
||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
name: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
onDeleteButtonClick: PropTypes.func,
|
||||
onDuplicateButtonClick: PropTypes.func,
|
||||
onMouseOut: PropTypes.func,
|
||||
onMouseOver: PropTypes.func,
|
||||
receivedBlocks: PropTypes.bool,
|
||||
selected: PropTypes.bool
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, {assetId, costumeURL}) => ({
|
||||
costumeURL: costumeURL || (assetId && state.vm.runtime.storage.get(assetId).encodeDataURI())
|
||||
const mapStateToProps = (state, {assetId, costumeURL, id}) => ({
|
||||
costumeURL: costumeURL || (assetId && state.vm.runtime.storage.get(assetId).encodeDataURI()),
|
||||
receivedBlocks: state.hoveredTarget.receivedBlocks &&
|
||||
state.hoveredTarget.sprite === id
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
dispatchSetHoveredSprite: spriteId => {
|
||||
dispatch(setHoveredSprite(spriteId));
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(SpriteSelectorItem);
|
||||
@@ -9,8 +9,6 @@ import {
|
||||
closeSpriteLibrary
|
||||
} from '../reducers/modals';
|
||||
|
||||
import {setHoveredSprite} from '../reducers/hovered-target-sprite';
|
||||
|
||||
import TargetPaneComponent from '../components/target-pane/target-pane.jsx';
|
||||
|
||||
class TargetPane extends React.Component {
|
||||
@@ -25,8 +23,6 @@ class TargetPane extends React.Component {
|
||||
'handleChangeSpriteY',
|
||||
'handleDeleteSprite',
|
||||
'handleDuplicateSprite',
|
||||
'handleMouseOutSprite',
|
||||
'handleMouseOverSprite',
|
||||
'handleSelectSprite'
|
||||
]);
|
||||
}
|
||||
@@ -54,12 +50,6 @@ class TargetPane extends React.Component {
|
||||
handleDuplicateSprite (id) {
|
||||
this.props.vm.duplicateSprite(id);
|
||||
}
|
||||
handleMouseOutSprite () {
|
||||
this.props.setHoveredSprite(null);
|
||||
}
|
||||
handleMouseOverSprite (id) {
|
||||
this.props.setHoveredSprite(id);
|
||||
}
|
||||
handleSelectSprite (id) {
|
||||
this.props.vm.setEditingTarget(id);
|
||||
}
|
||||
@@ -75,8 +65,6 @@ class TargetPane extends React.Component {
|
||||
onChangeSpriteY={this.handleChangeSpriteY}
|
||||
onDeleteSprite={this.handleDeleteSprite}
|
||||
onDuplicateSprite={this.handleDuplicateSprite}
|
||||
onMouseOutSprite={this.handleMouseOutSprite}
|
||||
onMouseOverSprite={this.handleMouseOverSprite}
|
||||
onSelectSprite={this.handleSelectSprite}
|
||||
/>
|
||||
);
|
||||
@@ -94,6 +82,7 @@ TargetPane.propTypes = {
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
editingTarget: state.targets.editingTarget,
|
||||
hoveredTarget: state.hoveredTarget,
|
||||
sprites: Object.keys(state.targets.sprites).reduce((sprites, k) => {
|
||||
let {direction, size, x, y, ...sprite} = state.targets.sprites[k];
|
||||
if (typeof direction !== 'undefined') direction = Math.round(direction);
|
||||
@@ -118,9 +107,6 @@ const mapDispatchToProps = dispatch => ({
|
||||
},
|
||||
onRequestCloseBackdropLibrary: () => {
|
||||
dispatch(closeBackdropLibrary());
|
||||
},
|
||||
setHoveredSprite: spriteId => {
|
||||
dispatch(setHoveredSprite(spriteId));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {connect} from 'react-redux';
|
||||
import {updateEditingTarget, updateTargets} from '../reducers/targets';
|
||||
import {updateBlockDrag} from '../reducers/block-drag';
|
||||
import {updateMonitors} from '../reducers/monitors';
|
||||
import {setReceivedBlocks} from '../reducers/hovered-target';
|
||||
|
||||
/*
|
||||
* Higher Order Component to manage events emitted by the VM
|
||||
@@ -51,8 +52,9 @@ const vmListenerHOC = function (WrappedComponent) {
|
||||
}
|
||||
}
|
||||
handleBlockDragEnd (blocks) {
|
||||
if (this.props.hoveredTargetSprite && this.props.hoveredTargetSprite !== this.props.editingTarget) {
|
||||
this.props.vm.shareBlocksToTarget(blocks, this.props.hoveredTargetSprite);
|
||||
if (this.props.hoveredSprite && this.props.hoveredSprite !== this.props.editingTarget) {
|
||||
this.props.vm.shareBlocksToTarget(blocks, this.props.hoveredSprite);
|
||||
this.props.onReceivedBlocks(true);
|
||||
}
|
||||
}
|
||||
handleKeyDown (e) {
|
||||
@@ -86,10 +88,13 @@ const vmListenerHOC = function (WrappedComponent) {
|
||||
const {
|
||||
/* eslint-disable no-unused-vars */
|
||||
attachKeyboardEvents,
|
||||
editingTarget,
|
||||
hoveredSprite,
|
||||
onBlockDragUpdate,
|
||||
onKeyDown,
|
||||
onKeyUp,
|
||||
onMonitorsUpdate,
|
||||
onReceivedBlocks,
|
||||
onTargetsUpdate,
|
||||
/* eslint-enable no-unused-vars */
|
||||
...props
|
||||
@@ -100,11 +105,12 @@ const vmListenerHOC = function (WrappedComponent) {
|
||||
VMListener.propTypes = {
|
||||
attachKeyboardEvents: PropTypes.bool,
|
||||
editingTarget: PropTypes.string,
|
||||
hoveredTargetSprite: PropTypes.string,
|
||||
hoveredSprite: PropTypes.string,
|
||||
onBlockDragUpdate: PropTypes.func.isRequired,
|
||||
onKeyDown: PropTypes.func,
|
||||
onKeyUp: PropTypes.func,
|
||||
onMonitorsUpdate: PropTypes.func.isRequired,
|
||||
onReceivedBlocks: PropTypes.func.isRequired,
|
||||
onTargetsUpdate: PropTypes.func.isRequired,
|
||||
vm: PropTypes.instanceOf(VM).isRequired
|
||||
};
|
||||
@@ -113,7 +119,7 @@ const vmListenerHOC = function (WrappedComponent) {
|
||||
};
|
||||
const mapStateToProps = state => ({
|
||||
vm: state.vm,
|
||||
hoveredTargetSprite: state.hoveredTargetSprite,
|
||||
hoveredSprite: state.hoveredTarget.sprite,
|
||||
editingTarget: state.targets.editingTarget
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
@@ -126,6 +132,9 @@ const vmListenerHOC = function (WrappedComponent) {
|
||||
},
|
||||
onBlockDragUpdate: areBlocksOverGui => {
|
||||
dispatch(updateBlockDrag(areBlocksOverGui));
|
||||
},
|
||||
onReceivedBlocks: receivedBlocks => {
|
||||
dispatch(setReceivedBlocks(receivedBlocks));
|
||||
}
|
||||
});
|
||||
return connect(
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import {combineReducers} from 'redux';
|
||||
import colorPickerReducer from './color-picker';
|
||||
import customProceduresReducer from './custom-procedures';
|
||||
import blockDragReducer from './block-drag';
|
||||
import hoveredTargetSpriteReducer from './hovered-target-sprite';
|
||||
import hoveredTargetReducer from './hovered-target';
|
||||
import intlReducer from './intl';
|
||||
import modalReducer from './modals';
|
||||
import monitorReducer from './monitors';
|
||||
@@ -17,7 +17,7 @@ export default combineReducers({
|
||||
blockDrag: blockDragReducer,
|
||||
colorPicker: colorPickerReducer,
|
||||
customProcedures: customProceduresReducer,
|
||||
hoveredTargetSprite: hoveredTargetSpriteReducer,
|
||||
hoveredTarget: hoveredTargetReducer,
|
||||
intl: intlReducer,
|
||||
stageSize: stageSizeReducer,
|
||||
modals: modalReducer,
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
const SET_HOVERED_SPRITE = 'scratch-gui/hovered-target-sprite/SET_HOVERED_SPRITE';
|
||||
|
||||
const initialState = null;
|
||||
|
||||
const reducer = function (state, action) {
|
||||
if (typeof state === 'undefined') state = initialState;
|
||||
switch (action.type) {
|
||||
case SET_HOVERED_SPRITE:
|
||||
return action.spriteId;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const setHoveredSprite = function (spriteId) {
|
||||
return {
|
||||
type: SET_HOVERED_SPRITE,
|
||||
spriteId: spriteId,
|
||||
meta: {
|
||||
throttle: 30
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export {
|
||||
reducer as default,
|
||||
setHoveredSprite
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
const SET_HOVERED_SPRITE = 'scratch-gui/hovered-target/SET_HOVERED_SPRITE';
|
||||
const SET_RECEIVED_BLOCKS = 'scratch-gui/hovered-target/SET_RECEIVED_BLOCKS';
|
||||
|
||||
const initialState = {
|
||||
sprite: null,
|
||||
receivedBlocks: false
|
||||
};
|
||||
|
||||
const reducer = function (state, action) {
|
||||
if (typeof state === 'undefined') state = initialState;
|
||||
switch (action.type) {
|
||||
case SET_HOVERED_SPRITE:
|
||||
return {
|
||||
sprite: action.spriteId,
|
||||
receivedBlocks: false
|
||||
};
|
||||
case SET_RECEIVED_BLOCKS:
|
||||
return {
|
||||
sprite: state.sprite,
|
||||
receivedBlocks: action.receivedBlocks
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const setHoveredSprite = function (spriteId) {
|
||||
return {
|
||||
type: SET_HOVERED_SPRITE,
|
||||
spriteId: spriteId,
|
||||
meta: {
|
||||
throttle: 30
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const setReceivedBlocks = function (receivedBlocks) {
|
||||
return {
|
||||
type: SET_RECEIVED_BLOCKS,
|
||||
receivedBlocks: receivedBlocks
|
||||
};
|
||||
};
|
||||
|
||||
export {
|
||||
reducer as default,
|
||||
setHoveredSprite,
|
||||
setReceivedBlocks
|
||||
};
|
||||
Reference in new issue
Block a user