Merge pull request #4 from LLK/develop

merge updates to my fork
This commit is contained in:
Jacob Bartles authored and GitHub committed 2018-04-03 15:41:01 -04:00
commit 7fb49eb1b2
53 files changed
+1478 -824

No files matched your search

+1 -4
View File
@@ -3,11 +3,8 @@ sudo: required
dist: trusty
addons:
chrome: stable
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
node_js:
- 6
- 8
cache:
directories:
- node_modules
+11 -11
View File
@@ -27,7 +27,7 @@
"react-dom": "^16.0.0"
},
"devDependencies": {
"autoprefixer": "^7.1.3",
"autoprefixer": "^8.1.0",
"babel-core": "^6.23.1",
"babel-eslint": "^8.0.1",
"babel-loader": "^7.1.0",
@@ -37,7 +37,7 @@
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.22.0",
"buffer-loader": "0.0.1",
"chromedriver": "2.35.0",
"chromedriver": "2.37.0",
"classnames": "2.2.5",
"copy-webpack-plugin": "^4.3.0",
"css-loader": "^0.28.7",
@@ -48,11 +48,11 @@
"eslint-config-scratch": "^5.0.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-react": "^7.5.1",
"file-loader": "1.1.9",
"file-loader": "1.1.11",
"get-float-time-domain-data": "0.1.0",
"get-user-media-promise": "1.1.1",
"gh-pages": "github:rschamp/gh-pages#publish-branch-to-subfolder",
"html-webpack-plugin": "^2.30.0",
"html-webpack-plugin": "^3.0.5",
"immutable": "3.8.2",
"jest": "^21.0.0",
"lodash.bindall": "4.4.0",
@@ -77,10 +77,10 @@
"react-ga": "2.4.1",
"react-intl": "2.4.0",
"react-intl-redux": "0.7.0",
"react-modal": "3.3.1",
"react-modal": "3.3.2",
"react-redux": "5.0.7",
"react-responsive": "4.0.3",
"react-style-proptype": "3.2.0",
"react-responsive": "4.1.0",
"react-style-proptype": "3.2.1",
"react-tabs": "2.2.1",
"react-test-renderer": "16.2.0",
"react-tooltip": "3.4.0",
@@ -89,12 +89,12 @@
"redux-throttle": "0.1.1",
"rimraf": "^2.6.1",
"scratch-audio": "0.1.0-prerelease.1516198804",
"scratch-blocks": "0.1.0-prerelease.1519256473",
"scratch-blocks": "0.1.0-prerelease.1522264400",
"scratch-l10n": "2.0.20180108132626",
"scratch-paint": "0.2.0-prerelease.20180302160120",
"scratch-render": "0.1.0-prerelease.1516837442",
"scratch-paint": "0.2.0-prerelease.20180403143543",
"scratch-render": "0.1.0-prerelease.1522346711",
"scratch-storage": "0.4.0",
"scratch-vm": "0.1.0-prerelease.1519681201-prerelease.1519681262",
"scratch-vm": "0.1.0-prerelease.1522355889-prerelease.1522355906",
"selenium-webdriver": "3.6.0",
"startaudiocontext": "1.2.1",
"style-loader": "^0.20.0",
+3 -2
View File
@@ -45,6 +45,7 @@ const Selector = props => {
id={index}
key={`asset-${index}`}
name={item.name}
number={index + 1 /* 1-indexed */}
selected={index === selectedItemIndex}
onClick={onItemClick}
onDeleteButtonClick={onDeleteClick}
@@ -59,9 +60,9 @@ const Selector = props => {
Selector.propTypes = {
buttons: PropTypes.arrayOf(PropTypes.shape({
message: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
img: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired
onClick: PropTypes.func
})),
items: PropTypes.arrayOf(PropTypes.shape({
url: PropTypes.string,
@@ -9,7 +9,7 @@ import styles from './browser-modal.css';
const messages = defineMessages({
label: {
id: 'gui.unsupportedBrowser.label',
defaultMessage: 'Internet Explorer is not supported',
defaultMessage: 'Browser is not supported',
description: ''
}
});
@@ -31,7 +31,7 @@ const BrowserModal = ({intl, ...props}) => (
<p>
{ /* eslint-disable max-len */ }
<FormattedMessage
defaultMessage="We're very sorry, but Scratch 3.0 does not support Internet Explorer. We recommend trying a newer browser such as Google Chrome, Mozilla Firefox, or Microsoft Edge."
defaultMessage="We're very sorry, but Scratch 3.0 does not support Internet Explorer, Opera or Silk. We recommend trying a newer browser such as Google Chrome, Mozilla Firefox, or Microsoft Edge."
description="Unsupported browser description"
id="gui.unsupportedBrowser.description"
/>
+17 -1
View File
@@ -1,3 +1,19 @@
.button {
.outlined-button {
cursor: pointer;
border-radius: .25rem;
font-weight: bold;
display: flex;
flex-direction: row;
align-items: center;
padding-left: .75rem;
padding-right: .75rem;
}
.icon {
margin-right: .5rem;
height: 1.5rem;
}
.content {
white-space: nowrap;
}
+18 -3
View File
@@ -6,25 +6,38 @@ import styles from './button.css';
const ButtonComponent = ({
className,
disabled,
iconClassName,
iconSrc,
onClick,
children,
...props
}) => {
if (props.disabled === true) {
if (disabled) {
onClick = function () {};
}
const icon = iconSrc && (
<img
className={classNames(iconClassName, styles.icon)}
draggable={false}
src={iconSrc}
/>
);
return (
<span
className={classNames(
styles.button,
styles.outlinedButton,
className
)}
role="button"
onClick={onClick}
{...props}
>
{children}
{icon}
<div className={styles.content}>{children}</div>
</span>
);
};
@@ -33,6 +46,8 @@ ButtonComponent.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
disabled: PropTypes.bool,
iconClassName: PropTypes.string,
iconSrc: PropTypes.string,
onClick: PropTypes.func.isRequired
};
-1
View File
@@ -25,7 +25,6 @@ const FilterComponent = props => {
src={filterIcon}
/>
<input
autoFocus
className={styles.filterInput}
placeholder={placeholderText}
type="text"
+7 -1
View File
@@ -34,6 +34,10 @@ const messages = defineMessages({
}
});
// Cache this value to only retreive it once the first time.
// Assume that it doesn't change for a session.
let isRendererSupported = null;
const GUIComponent = props => {
const {
activeTabIndex,
@@ -69,7 +73,9 @@ const GUIComponent = props => {
tabSelected: classNames(tabStyles.reactTabsTabSelected, styles.isSelected)
};
const isRendererSupported = Renderer.isSupported();
if (isRendererSupported === null) {
isRendererSupported = Renderer.isSupported();
}
return (
<Box
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="8px" height="5px" viewBox="0 0 8 5" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>dropdown-caret</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="dropdown-caret" fill="#FFFFFF">
<path d="M4,5 C3.72520708,5 3.45163006,4.89695045 3.24127973,4.68965311 L0.314613572,1.80666227 C-0.104871191,1.39326583 -0.104871191,0.724642023 0.314613572,0.310047331 C0.732882438,-0.10334911 7.26711756,-0.10334911 7.68538643,0.310047331 C8.10487119,0.723443772 8.10487119,1.39326583 7.68538643,1.80666227 L4.75993617,4.68965311 C4.54958583,4.89695045 4.27600882,5 4,5"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 904 B

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>Language</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" opacity="0.25" stroke-linejoin="round">
<g id="Language" stroke="#000000" stroke-width="1.25">
<g transform="translate(2.000000, 2.000000)">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="Language" stroke="#FFFFFF" stroke-width="1.25">
<g id="language" transform="translate(2.000000, 2.000000)">
<path d="M15.6352,8.11294118 C15.6352,12.2682353 12.2667294,15.6357647 8.11237647,15.6357647 C3.95708235,15.6357647 0.588611765,12.2682353 0.588611765,8.11294118 C0.588611765,3.95764706 3.95708235,0.589176471 8.11237647,0.589176471 C12.2667294,0.589176471 15.6352,3.95764706 15.6352,8.11294118 Z" id="Stroke-1"></path>
<path d="M11.9808,8.11661176 C11.9808,9.74955294 11.7153882,11.2601412 11.2542118,12.4921412 C10.5558588,14.3933176 9.40762353,15.6347294 8.11068235,15.6347294 C6.81374118,15.6347294 5.66927059,14.3933176 4.96715294,12.4921412 C4.51068235,11.2601412 4.24432941,9.74955294 4.24432941,8.11661176 C4.24432941,6.48272941 4.51068235,4.97308235 4.96715294,3.74108235 C5.66927059,1.82955294 6.81374118,0.588141176 8.11068235,0.588141176 C9.40762353,0.588141176 10.5558588,1.82955294 11.2542118,3.74108235 C11.7153882,4.97308235 11.9808,6.48272941 11.9808,8.11661176 Z" id="Stroke-3"></path>
<path d="M0.955011765,10.2811294 L15.2684235,10.2811294" id="Stroke-5"></path>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -9,8 +9,11 @@
}
.language-icon {
height: 2rem;
display: none;
height: 1.5rem;
}
.disabled {
opacity: .5;
}
.language-select {
@@ -1,27 +1,22 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import Box from '../box/box.jsx';
import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx';
import locales from 'scratch-l10n';
import languageIcon from './language-icon.svg';
import dropdownCaret from './dropdown-caret.svg';
import styles from './language-selector.css';
const LanguageSelector = ({
currentLocale,
onChange,
open,
...props
}) => (
<Box {...props}>
<ComingSoonTooltip
place="bottom"
tooltipId="language-selector"
>
<div className={styles.group}>
<img
className={styles.languageIcon}
src={languageIcon}
/>
<div className={styles.group}>
{open ? (
<select
disabled
aria-label="language selector"
@@ -38,15 +33,27 @@ const LanguageSelector = ({
</option>
))}
</select>
</div>
</ComingSoonTooltip>
) : (
<React.Fragment>
<img
className={classNames(styles.languageIcon, styles.disabled)}
src={languageIcon}
/>
<img
className={classNames(styles.dropdownCaret, styles.disabled)}
src={dropdownCaret}
/>
</React.Fragment>
)}
</div>
</Box>
);
LanguageSelector.propTypes = {
currentLocale: PropTypes.string,
onChange: PropTypes.func
onChange: PropTypes.func,
open: PropTypes.boolean
};
export default LanguageSelector;
@@ -26,6 +26,7 @@ const LoadButtonComponent = ({
</ButtonComponent>
<input
disabled
accept=".sb2,.sb3"
className={styles.fileInput}
ref={inputRef}
type="file"
+17 -4
View File
@@ -29,19 +29,18 @@
margin-top: -4px;
}
.topBlock {
.top-block {
animation: top-slide-in 1.5s ease infinite;
}
.middleBlock {
.middle-block {
animation: middle-slide-in 1.5s ease infinite;
}
.bottomBlock {
.bottom-block {
animation: bottom-slide-in 1.5s ease infinite;
}
@keyframes top-slide-in {
0% {
transform: translateY(50px);
@@ -87,3 +86,17 @@
opacity: 1;
}
}
.message-container-outer {
height: 30px;
overflow: hidden;
}
.message-container-inner {
transition: transform 0.5s;
}
.message {
height: 20px;
margin: 5px 0;
}
+165 -131
View File
@@ -5,140 +5,174 @@ import styles from './loader.css';
import topBlock from './top-block.svg';
import middleBlock from './middle-block.svg';
import bottomBlock from './bottom-block.svg';
const LoaderComponent = () => {
const messages = [
{
message: (
<FormattedMessage
defaultMessage="Creating blocks …"
description="One of the loading messages"
id="gui.loader.message1"
/>
),
weight: 50
},
{
message: (
<FormattedMessage
defaultMessage="Loading sprites …"
description="One of the loading messages"
id="gui.loader.message2"
/>
),
weight: 50
},
{
message: (
<FormattedMessage
defaultMessage="Loading sounds …"
description="One of the loading messages"
id="gui.loader.message3"
/>
),
weight: 50
},
{
message: (
<FormattedMessage
defaultMessage="Loading extensions …"
description="One of the loading messages"
id="gui.loader.message4"
/>
),
weight: 50
},
{
message: (
<FormattedMessage
defaultMessage="Creating blocks …"
description="One of the loading messages"
id="gui.loader.message1"
/>
),
weight: 20
},
{
message: (
<FormattedMessage
defaultMessage="Herding cats …"
description="One of the loading messages"
id="gui.loader.message5"
/>
),
weight: 1
},
{
message: (
<FormattedMessage
defaultMessage="Transmitting nanos …"
description="One of the loading messages"
id="gui.loader.message6"
/>
),
weight: 1
},
{
message: (
<FormattedMessage
defaultMessage="Inflating gobos …"
description="One of the loading messages"
id="gui.loader.message7"
/>
),
weight: 1
},
{
message: (
<FormattedMessage
defaultMessage="Preparing emojiis …"
description="One of the loading messages"
id="gui.loader.message8"
/>
),
weight: 1
}
];
let message;
const sum = messages.reduce((acc, m) => acc + m.weight, 0);
let rand = sum * Math.random();
for (let i = 0; i < messages.length; i++) {
rand -= messages[i].weight;
if (rand <= 0) {
message = messages[i].message;
break;
}
const messages = [
{
message: (
<FormattedMessage
defaultMessage="Creating blocks …"
description="One of the loading messages"
id="gui.loader.message1"
/>
),
weight: 50
},
{
message: (
<FormattedMessage
defaultMessage="Loading sprites …"
description="One of the loading messages"
id="gui.loader.message2"
/>
),
weight: 50
},
{
message: (
<FormattedMessage
defaultMessage="Loading sounds …"
description="One of the loading messages"
id="gui.loader.message3"
/>
),
weight: 50
},
{
message: (
<FormattedMessage
defaultMessage="Loading extensions …"
description="One of the loading messages"
id="gui.loader.message4"
/>
),
weight: 50
},
{
message: (
<FormattedMessage
defaultMessage="Creating blocks …"
description="One of the loading messages"
id="gui.loader.message1"
/>
),
weight: 20
},
{
message: (
<FormattedMessage
defaultMessage="Herding cats …"
description="One of the loading messages"
id="gui.loader.message5"
/>
),
weight: 1
},
{
message: (
<FormattedMessage
defaultMessage="Transmitting nanos …"
description="One of the loading messages"
id="gui.loader.message6"
/>
),
weight: 1
},
{
message: (
<FormattedMessage
defaultMessage="Inflating gobos …"
description="One of the loading messages"
id="gui.loader.message7"
/>
),
weight: 1
},
{
message: (
<FormattedMessage
defaultMessage="Preparing emojis …"
description="One of the loading messages"
id="gui.loader.message8"
/>
),
weight: 1
}
];
return (
<div className={styles.background}>
<div className={styles.container}>
<div className={styles.blockAnimation}>
<img
className={styles.topBlock}
src={topBlock}
/>
<img
className={styles.middleBlock}
src={middleBlock}
/>
<img
className={styles.bottomBlock}
src={bottomBlock}
/>
class LoaderComponent extends React.Component {
constructor (props) {
super(props);
this.state = {
messageNumber: 0
};
}
componentDidMount () {
this.chooseRandomMessage();
// Start an interval to choose a new message every 5 seconds
this.intervalId = setInterval(() => {
this.chooseRandomMessage();
}, 5000);
}
componentWillUnmount () {
clearInterval(this.intervalId);
}
chooseRandomMessage () {
let messageNumber;
const sum = messages.reduce((acc, m) => acc + m.weight, 0);
let rand = sum * Math.random();
for (let i = 0; i < messages.length; i++) {
rand -= messages[i].weight;
if (rand <= 0) {
messageNumber = i;
break;
}
}
this.setState({messageNumber});
}
render () {
return (
<div className={styles.background}>
<div className={styles.container}>
<div className={styles.blockAnimation}>
<img
className={styles.topBlock}
src={topBlock}
/>
<img
className={styles.middleBlock}
src={middleBlock}
/>
<img
className={styles.bottomBlock}
src={bottomBlock}
/>
</div>
<h1 className={styles.title}>
<FormattedMessage
defaultMessage="Loading Project"
description="Main loading message"
id="gui.loader.headline"
/>
</h1>
<div className={styles.messageContainerOuter}>
<div
className={styles.messageContainerInner}
style={{transform: `translate(0, -${this.state.messageNumber * 25}px)`}}
>
{messages.map((m, i) => (
<div
className={styles.message}
key={i}
>
{m.message}
</div>
))}
</div>
</div>
</div>
<h1 className={styles.title}>
<FormattedMessage
defaultMessage="Loading Project"
description="Main loading message"
id="gui.loader.headline"
/>
</h1>
<p>{message}</p>
</div>
</div>
);
};
);
}
}
export default LoaderComponent;
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>See Community</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="See-Community" fill="#FFFFFF">
<path d="M11.1795886,5.69863689 C10.0344146,5.50396503 8.8909358,5.87638076 8.11109855,6.59582023 L9.1028481,7.58526111 C9.48429024,7.97460483 9.2130425,8.63564275 8.66207052,8.63564275 L4.61878391,8.63564275 C4.27972423,8.63564275 4,8.35633095 4,8.0169248 L4,3.98044614 C4,3.42944014 4.66116637,3.15943873 5.05108499,3.53947206 L5.89873418,4.38587144 C6.67009494,3.78492788 7.56860307,3.35326419 8.50949367,3.15012834 C9.60296112,2.91398291 10.7379634,2.95630288 11.7814195,3.27793465 C13.8835895,3.91273418 15.5110759,5.6732449 15.977283,7.68767544 C16.0874774,8.17012309 15.7823237,8.66103473 15.2991637,8.77106665 C14.8499096,8.88109857 14.409132,8.62717876 14.2480787,8.21244306 L14.2480787,8.20397906 C13.7310127,6.85735764 12.4849684,5.89246235 11.1795886,5.69863689 Z M8.82041139,14.3015249 C9.96473779,14.4953503 11.1090642,14.123781 11.8889014,13.4043415 L10.8971519,12.4140542 C10.5157098,12.0247105 10.7861099,11.364519 11.3379295,11.364519 L15.3803684,11.364519 C15.7202758,11.364519 16,11.6438308 16,11.9823906 L16,16.0197156 C16,16.5698752 15.337986,16.840723 14.9480674,16.4598433 L14.1004182,15.6134439 C13.3290574,16.2143875 12.4313969,16.6460512 11.4896587,16.849187 C10.3961912,17.0861788 9.26118897,17.0438589 8.21858047,16.7222271 C6.11641049,16.0874276 4.48892405,14.3269169 4.022717,12.3124863 C3.9125226,11.8300387 4.21682866,11.339127 4.70083635,11.2290951 C5.15009042,11.1190632 5.59002034,11.372983 5.75192134,11.7877187 L5.75192134,11.7961827 C6.26813969,13.1419577 7.51503165,14.106853 8.82041139,14.3015249 Z" id="see-community" transform="translate(10.000000, 10.000000) rotate(90.000000) translate(-10.000000, -10.000000) "></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+97 -42
View File
@@ -6,24 +6,26 @@
flex-direction: row;
justify-content: space-between;
flex-wrap: nowrap;
/*
For most things, we shouldn't explicitly set height, and let the
content push the element to whatever fits. Using a fixed height
instead, will help us subtract the value we assign from the body,
adding up to a perfect 100%. This means we don't need to set
overflow: hidden, which makes it hard to debug. border-box
simplifies by all of this by removing padding from the equation.
/*
For most things, we shouldn't explicitly set height, and let the
content push the element to whatever fits. Using a fixed height
instead, will help us subtract the value we assign from the body,
adding up to a perfect 100%. This means we don't need to set
overflow: hidden, which makes it hard to debug. border-box
simplifies by all of this by removing padding from the equation.
*/
box-sizing: border-box;
height: $menu-bar-height;
height: $menu-bar-height;
/*
@todo: This adds ~20px in Chrome, when scrolling to the right,
/*
@todo: This adds ~20px in Chrome, when scrolling to the right,
but fixes [FFx + Safari] [resize window down + scroll to the right] bug.
width: 100%;
width: 100%;
*/
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: .75rem;
font-weight: bold;
background-color: $motion-primary;
color: white;
}
@@ -33,18 +35,13 @@
flex-direction: row;
justify-content: flex-start;
flex-wrap: nowrap;
}
/*
Using a wrapper so when logo is hovered, it transforms via its center point
@todo: not sure if this is needed
*/
.logo-wrapper {
align-items: center;
}
.scratch-logo {
height: $menu-bar-height;
height: $menu-bar-height;
padding: 0.8rem 0;
vertical-align: middle;
}
.scratch-logo:hover {
@@ -53,43 +50,101 @@
transition: all .075s ease-in;
}
.title {
display: inline-block;
margin: 0 2rem;
}
.menu-item {
display: block;
padding: 0 1.5rem;
line-height: $menu-bar-height;
padding: 0 0.25rem;
cursor: pointer;
text-decoration: none;
color: $motion-tertiary;
color: #fff;
user-select: none;
align-self: center;
}
.feedback-button-wrapper {
align-self: center;
padding: 0 .5rem;
line-height: $menu-bar-height;
.file-group {
display: flex;
flex-direction: row;
align-items: center;
}
.file-group .menu-item {
padding: 0 0.75rem;
}
.feedback-button {
border-radius: 5px;
padding: .75rem;
background-color: #FFF;
cursor: pointer;
font-size: .75rem;
font-weight: bold;
color: $motion-primary;
height: 34px;
}
.feedback-button-icon {
vertical-align: middle;
.divider {
border-right: 1px dashed $menubar-gray;
margin: 0 .5rem;
height: 34px;
}
.feedback-button-icon {
.title-field {
border: 1px dashed $menubar-gray;
border-radius: .25rem;
width: 12rem;
height: 34px;
background-color: transparent;
padding: .5rem;
}
.title-field,
.title-field::placeholder {
color: #fff;
font-weight: bold;
font-size: .8rem;
}
.share-button {
background: #FFAB19;
height: 32px;
box-shadow: 0 0 0 1px rgba(0,0,0,.1);
}
.community-button {
height: 32px;
box-shadow: 0 0 0 1px rgba(0,0,0,.1);
}
.community-button-icon {
height: 1.25rem;
}
.coming-soon >:not(.coming-soon-tooltip) {
opacity: 0.5;
}
.account-info-wrapper {
display: flex;
flex-direction: row;
padding: 0 .5rem;
align-items: center;
}
.mystuff-icon {
margin-right: .5rem;
width: 1.5rem;
height: 1.5rem;
height: 1rem;
}
.account-nav-menu, .mystuff-button {
padding: 0 .25rem;
display: flex;
flex-direction: row;
align-items: center;
}
.profile-icon {
margin-right: .5rem;
width: 2rem;
height: 34px;
border-radius: 0.25rem;
}
.dropdown-caret-icon {
margin-left: .5rem;
width: 0.5rem;
height: 0.5rem;
}
+132 -24
View File
@@ -6,15 +6,18 @@ import React from 'react';
import Box from '../box/box.jsx';
import Button from '../button/button.jsx';
import LoadButton from '../../containers/load-button.jsx';
import SaveButton from '../../containers/save-button.jsx';
import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx';
import LanguageSelector from '../../containers/language-selector.jsx';
import {openFeedbackForm} from '../../reducers/modals';
import styles from './menu-bar.css';
import mystuffIcon from './icon--mystuff.png';
import profileIcon from './icon--profile.png';
import feedbackIcon from './icon--feedback.svg';
import communityIcon from './icon--see-community.svg';
import dropdownCaret from '../language-selector/dropdown-caret.svg';
import scratchLogo from './scratch-logo.svg';
const MenuBar = props => (
@@ -24,37 +27,142 @@ const MenuBar = props => (
})}
>
<div className={styles.mainMenu}>
<div className={classNames(styles.logoWrapper, styles.menuItem)}>
<img
alt="Scratch"
className={styles.scratchLogo}
draggable={false}
src={scratchLogo}
/>
<div className={styles.fileGroup}>
<div className={classNames(styles.logoWrapper, styles.menuItem)}>
<img
alt="Scratch"
className={styles.scratchLogo}
draggable={false}
src={scratchLogo}
/>
</div>
<div className={classNames(styles.menuItem)}>
<ComingSoonTooltip
className={styles.comingSoon}
place="bottom"
tooltipClassName={styles.comingSoonTooltip}
tooltipId="menubar-selector"
>
<LanguageSelector />
</ComingSoonTooltip>
</div>
<div className={classNames(styles.menuItem)}>
<ComingSoonTooltip
className={styles.comingSoon}
place="bottom"
tooltipClassName={styles.comingSoonTooltip}
tooltipId="file-menu"
>
<div className={classNames(styles.fileMenu)}>File</div>
</ComingSoonTooltip>
</div>
<div className={classNames(styles.menuItem)}>
<ComingSoonTooltip
className={styles.comingSoon}
place="bottom"
tooltipClassName={styles.comingSoonTooltip}
tooltipId="edit-menu"
>
<div className={classNames(styles.editMenu)}>Edit</div>
</ComingSoonTooltip>
</div>
</div>
<div className={classNames(styles.divider)} />
<div className={classNames(styles.menuItem)}>
<ComingSoonTooltip
className={styles.comingSoon}
place="bottom"
tooltipClassName={styles.comingSoonTooltip}
tooltipId="title-field"
>
<input
disabled
className={classNames(styles.titleField)}
placeholder="Untitled-1"
/>
</ComingSoonTooltip>
</div>
<div className={classNames(styles.menuItem)}>
<ComingSoonTooltip
className={styles.comingSoon}
place="bottom"
tooltipClassName={styles.comingSoonTooltip}
tooltipId="share-button"
>
<Button className={classNames(styles.shareButton)}>
<FormattedMessage
defaultMessage="Share"
description="Label for project share button"
id="gui.menuBar.share"
/>
</Button>
</ComingSoonTooltip>
</div>
<div className={classNames(styles.menuItem, styles.communityButtonWrapper)}>
<ComingSoonTooltip
className={styles.comingSoon}
place="bottom"
tooltipClassName={styles.comingSoonTooltip}
tooltipId="community-button"
>
<Button
className={classNames(styles.communityButton)}
iconClassName={styles.communityButtonIcon}
iconSrc={communityIcon}
>
<FormattedMessage
defaultMessage="See Community"
description="Label for see community button"
id="gui.menuBar.seeCommunity"
/>
</Button>
</ComingSoonTooltip>
</div>
<SaveButton className={styles.menuItem} />
<LoadButton className={styles.menuItem} />
<LanguageSelector className={styles.menuItem} />
</div>
<div className={styles.feedbackButtonWrapper}>
<div className={classNames(styles.menuItem, styles.feedbackButtonWrapper)}>
<Button
className={styles.feedbackButton}
iconSrc={feedbackIcon}
onClick={props.onGiveFeedback}
>
<img
className={styles.feedbackButtonIcon}
draggable={false}
src={feedbackIcon}
<FormattedMessage
defaultMessage="Give Feedback"
description="Label for feedback form modal button"
id="gui.menuBar.giveFeedback"
/>
<span className={styles.feedbackText}>
<FormattedMessage
defaultMessage="Give Feedback"
description="Label for feedback form modal button"
id="gui.menuBar.giveFeedback"
/>
</span>
</Button>
</div>
<div className={styles.accountInfoWrapper}>
<ComingSoonTooltip
className={styles.comingSoon}
place="bottom"
tooltipId="mystuff"
>
<div className={styles.mystuffButton}>
<img
className={styles.mystuffIcon}
src={mystuffIcon}
/>
</div>
</ComingSoonTooltip>
<ComingSoonTooltip
className={styles.comingSoon}
place="left"
tooltipId="account-nav"
>
<div className={styles.accountNavMenu}>
<img
className={styles.profileIcon}
src={profileIcon}
/>
<span>scratch-cat</span>
<img
className={styles.dropdownCaretIcon}
src={dropdownCaret}
/>
</div>
</ComingSoonTooltip>
</div>
</Box>
);
@@ -56,3 +56,11 @@
right: 0.125rem;
z-index: 2;
}
.number {
position: absolute;
top: 0.125rem;
left: 0.125rem;
font-size: 0.625rem;
z-index: 2;
}
@@ -31,6 +31,9 @@ const SpriteSelectorItem = props => (
onClick={props.onDeleteButtonClick}
/>
) : null }
{typeof props.number === 'undefined' ? null : (
<div className={styles.number}>{props.number}</div>
)}
{props.costumeURL ? (
<CostumeCanvas
className={styles.spriteImage}
@@ -69,6 +72,7 @@ SpriteSelectorItem.propTypes = {
className: PropTypes.string,
costumeURL: PropTypes.string,
name: PropTypes.string.isRequired,
number: PropTypes.number,
onClick: PropTypes.func,
onDeleteButtonClick: PropTypes.func,
onDuplicateButtonClick: PropTypes.func,
@@ -94,12 +94,12 @@ const StageSelector = props => {
}, {
title: intl.formatMessage(messages.addBackdropFromSurprise),
img: surpriseIcon,
onClick: onSurpriseBackdropClick // TODO NEED REAL FUNCTION
onClick: onSurpriseBackdropClick
}, {
title: intl.formatMessage(messages.addBackdropFromPaint),
img: paintIcon,
onClick: onEmptyBackdropClick // TODO NEED REAL FUNCTION
onClick: onEmptyBackdropClick
}
]}
title={intl.formatMessage(messages.addBackdropFromLibrary)}
@@ -4,7 +4,6 @@ import React from 'react';
import VM from 'scratch-vm';
import SpriteLibrary from '../../containers/sprite-library.jsx';
import BackdropLibrary from '../../containers/backdrop-library.jsx';
import SpriteSelectorComponent from '../sprite-selector/sprite-selector.jsx';
import StageSelector from '../../containers/stage-selector.jsx';
@@ -17,7 +16,6 @@ import styles from './target-pane.css';
* @returns {React.Component} rendered component
*/
const TargetPane = ({
backdropLibraryVisible,
editingTarget,
hoveredTarget,
spriteLibraryVisible,
@@ -33,7 +31,6 @@ const TargetPane = ({
onSurpriseSpriteClick,
onPaintSpriteClick,
onRequestCloseSpriteLibrary,
onRequestCloseBackdropLibrary,
onSelectSprite,
raiseSprites,
stage,
@@ -83,12 +80,6 @@ const TargetPane = ({
onRequestClose={onRequestCloseSpriteLibrary}
/>
) : null}
{backdropLibraryVisible ? (
<BackdropLibrary
vm={vm}
onRequestClose={onRequestCloseBackdropLibrary}
/>
) : null}
</div>
</div>
</div>
@@ -113,7 +104,6 @@ const spriteShape = PropTypes.shape({
});
TargetPane.propTypes = {
backdropLibraryVisible: PropTypes.bool,
editingTarget: PropTypes.string,
extensionLibraryVisible: PropTypes.bool,
hoveredTarget: PropTypes.shape({
@@ -130,7 +120,6 @@ TargetPane.propTypes = {
onDuplicateSprite: PropTypes.func,
onNewSpriteClick: PropTypes.func,
onPaintSpriteClick: PropTypes.func,
onRequestCloseBackdropLibrary: PropTypes.func,
onRequestCloseExtensionLibrary: PropTypes.func,
onRequestCloseSpriteLibrary: PropTypes.func,
onSelectSprite: PropTypes.func,
+1 -6
View File
@@ -23,11 +23,7 @@ class BackdropLibrary extends React.Component {
bitmapResolution: item.info.length > 2 ? item.info[2] : 1,
skinId: null
};
this.props.vm.addBackdrop(item.md5, vmBackdrop).then(() => {
if (this.props.onNewBackdrop) {
this.props.onNewBackdrop();
}
});
this.props.vm.addBackdrop(item.md5, vmBackdrop);
analytics.event({
category: 'library',
action: 'Select Backdrop',
@@ -47,7 +43,6 @@ class BackdropLibrary extends React.Component {
}
BackdropLibrary.propTypes = {
onNewBackdrop: PropTypes.func,
onRequestClose: PropTypes.func,
vm: PropTypes.instanceOf(VM).isRequired
};
+4 -2
View File
@@ -95,9 +95,11 @@ class Blocks extends React.Component {
}
if (prevProps.toolboxXML !== this.props.toolboxXML) {
const selectedCategoryName = this.workspace.toolbox_.getSelectedItem().name_;
const categoryName = this.workspace.toolbox_.getSelectedCategoryName();
const offset = this.workspace.toolbox_.getCategoryScrollOffset();
this.workspace.updateToolbox(this.props.toolboxXML);
this.workspace.toolbox_.setSelectedCategoryByName(selectedCategoryName);
const currentCategoryPos = this.workspace.toolbox_.getCategoryPositionByName(categoryName);
this.workspace.toolbox_.setFlyoutScrollPos(currentCategoryPos + offset);
}
if (this.props.isVisible === prevProps.isVisible) {
return;
+1 -4
View File
@@ -23,9 +23,7 @@ class CostumeLibrary extends React.PureComponent {
bitmapResolution: item.info.length > 2 ? item.info[2] : 1,
skinId: null
};
this.props.vm.addCostume(item.md5, vmCostume).then(() => {
this.props.onNewCostume();
});
this.props.vm.addCostume(item.md5, vmCostume);
analytics.event({
category: 'library',
action: 'Select Costume',
@@ -45,7 +43,6 @@ class CostumeLibrary extends React.PureComponent {
}
CostumeLibrary.propTypes = {
onNewCostume: PropTypes.func.isRequired,
onRequestClose: PropTypes.func,
vm: PropTypes.instanceOf(VM).isRequired
};
+36 -28
View File
@@ -7,10 +7,12 @@ import VM from 'scratch-vm';
import AssetPanel from '../components/asset-panel/asset-panel.jsx';
import PaintEditorWrapper from './paint-editor-wrapper.jsx';
import CostumeLibrary from './costume-library.jsx';
import BackdropLibrary from './backdrop-library.jsx';
import {connect} from 'react-redux';
import {
closeCostumeLibrary,
closeBackdropLibrary,
openCostumeLibrary,
openBackdropLibrary
} from '../reducers/modals';
@@ -65,7 +67,6 @@ class CostumeTab extends React.Component {
'handleSelectCostume',
'handleDeleteCostume',
'handleDuplicateCostume',
'handleNewCostume',
'handleNewBlankCostume',
'handleSurpriseCostume',
'handleSurpriseBackdrop'
@@ -90,8 +91,24 @@ class CostumeTab extends React.Component {
} = nextProps;
const target = editingTarget && sprites[editingTarget] ? sprites[editingTarget] : stage;
if (target && target.costumes && this.state.selectedCostumeIndex > target.costumes.length - 1) {
this.setState({selectedCostumeIndex: target.costumes.length - 1});
if (!target || !target.costumes) {
return;
}
if (this.props.editingTarget === editingTarget) {
// If costumes have been added or removed, change costumes to the editing target's
// current costume.
const oldTarget = this.props.sprites[editingTarget] ?
this.props.sprites[editingTarget] : this.props.stage;
// @todo: Find and switch to the index of the costume that is new. This is blocked by
// https://github.com/LLK/scratch-vm/issues/967
// Right now, you can land on the wrong costume if a costume changing script is running.
if (oldTarget.costumeCount !== target.costumeCount) {
this.setState({selectedCostumeIndex: target.currentCostume});
}
} else {
// If switching editing targets, update the costume index
this.setState({selectedCostumeIndex: target.currentCostume});
}
}
handleSelectCostume (costumeIndex) {
@@ -102,14 +119,7 @@ class CostumeTab extends React.Component {
this.props.vm.deleteCostume(costumeIndex);
}
handleDuplicateCostume (costumeIndex) {
this.props.vm.duplicateCostume(costumeIndex).then(() => {
this.setState({selectedCostumeIndex: costumeIndex + 1});
});
}
handleNewCostume () {
if (!this.props.vm.editingTarget) return;
const costumes = this.props.vm.editingTarget.getCostumes() || [];
this.setState({selectedCostumeIndex: Math.max(costumes.length - 1, 0)});
this.props.vm.duplicateCostume(costumeIndex);
}
handleNewBlankCostume () {
const emptyItem = costumeLibraryContent.find(item => (
@@ -124,9 +134,7 @@ class CostumeTab extends React.Component {
skinId: null
};
this.props.vm.addCostume(emptyItem.md5, vmCostume).then(() => {
this.handleNewCostume();
});
this.props.vm.addCostume(emptyItem.md5, vmCostume);
}
handleSurpriseCostume () {
const item = costumeLibraryContent[Math.floor(Math.random() * costumeLibraryContent.length)];
@@ -137,9 +145,7 @@ class CostumeTab extends React.Component {
bitmapResolution: item.info.length > 2 ? item.info[2] : 1,
skinId: null
};
this.props.vm.addCostume(item.md5, vmCostume).then(() => {
this.handleNewCostume();
});
this.props.vm.addCostume(item.md5, vmCostume);
}
handleSurpriseBackdrop () {
const item = backdropLibraryContent[Math.floor(Math.random() * backdropLibraryContent.length)];
@@ -150,27 +156,22 @@ class CostumeTab extends React.Component {
bitmapResolution: item.info.length > 2 ? item.info[2] : 1,
skinId: null
};
this.props.vm.addCostume(item.md5, vmCostume).then(() => {
this.handleNewCostume();
});
this.props.vm.addCostume(item.md5, vmCostume);
}
render () {
// For paint wrapper
const {
intl,
onNewLibraryBackdropClick,
onNewLibraryCostumeClick,
backdropLibraryVisible,
costumeLibraryVisible,
onRequestCloseBackdropLibrary,
onRequestCloseCostumeLibrary,
...props
} = this.props;
const {
editingTarget,
sprites,
stage,
vm
} = props;
} = this.props;
const target = editingTarget && sprites[editingTarget] ? sprites[editingTarget] : stage;
@@ -218,7 +219,6 @@ class CostumeTab extends React.Component {
>
{target.costumes ?
<PaintEditorWrapper
{...props}
selectedCostumeIndex={this.state.selectedCostumeIndex}
/> :
null
@@ -226,10 +226,15 @@ class CostumeTab extends React.Component {
{costumeLibraryVisible ? (
<CostumeLibrary
vm={vm}
onNewCostume={this.handleNewCostume}
onRequestClose={onRequestCloseCostumeLibrary}
/>
) : null}
{backdropLibraryVisible ? (
<BackdropLibrary
vm={vm}
onRequestClose={onRequestCloseBackdropLibrary}
/>
) : null}
</AssetPanel>
);
}
@@ -278,6 +283,9 @@ const mapDispatchToProps = dispatch => ({
e.preventDefault();
dispatch(openCostumeLibrary());
},
onRequestCloseBackdropLibrary: () => {
dispatch(closeBackdropLibrary());
},
onRequestCloseCostumeLibrary: () => {
dispatch(closeCostumeLibrary());
}
+7 -2
View File
@@ -30,12 +30,17 @@ class ErrorBoundary extends React.Component {
}
handleReload () {
window.location.replace(window.location.origin);
window.location.replace(window.location.origin + window.location.pathname);
}
render () {
if (this.state.hasError) {
if (platform.name === 'IE') {
// don't use array.includes because that's something that causes IE to crash.
if (
platform.name === 'IE' ||
platform.name === 'Opera' ||
platform.name === 'Opera Mini' ||
platform.name === 'Silk') {
return <BrowserModalComponent onBack={this.handleBack} />;
}
return <CrashMessageComponent onReload={this.handleReload} />;
+28 -10
View File
@@ -20,25 +20,39 @@ class GUI extends React.Component {
constructor (props) {
super(props);
this.state = {
loading: true
loading: true,
loadingError: false,
errorMessage: ''
};
}
componentDidMount () {
this.audioEngine = new AudioEngine();
this.props.vm.attachAudioEngine(this.audioEngine);
this.props.vm.loadProject(this.props.projectData).then(() => {
this.setState({loading: false}, () => {
this.props.vm.setCompatibilityMode(true);
this.props.vm.start();
this.props.vm.loadProject(this.props.projectData)
.then(() => {
this.setState({loading: false}, () => {
this.props.vm.setCompatibilityMode(true);
this.props.vm.start();
});
})
.catch(e => {
// Need to catch this error and update component state so that
// error page gets rendered if project failed to load
this.setState({loadingError: true, errorMessage: e});
});
});
}
componentWillReceiveProps (nextProps) {
if (this.props.projectData !== nextProps.projectData) {
this.setState({loading: true}, () => {
this.props.vm.loadProject(nextProps.projectData).then(() => {
this.setState({loading: false});
});
this.props.vm.loadProject(nextProps.projectData)
.then(() => {
this.setState({loading: false});
})
.catch(e => {
// Need to catch this error and update component state so that
// error page gets rendered if project failed to load
this.setState({loadingError: true, errorMessage: e});
});
});
}
}
@@ -46,16 +60,18 @@ class GUI extends React.Component {
this.props.vm.stopAll();
}
render () {
if (this.state.loadingError) throw new Error(`Failed to load project: ${this.state.errorMessage}`);
const {
children,
fetchingProject,
loadingStateVisible,
projectData, // eslint-disable-line no-unused-vars
vm,
...componentProps
} = this.props;
return (
<GUIComponent
loading={fetchingProject || this.state.loading}
loading={fetchingProject || this.state.loading || loadingStateVisible}
vm={vm}
{...componentProps}
>
@@ -70,6 +86,7 @@ GUI.propTypes = {
feedbackFormVisible: PropTypes.bool,
fetchingProject: PropTypes.bool,
importInfoVisible: PropTypes.bool,
loadingStateVisible: PropTypes.bool,
previewInfoVisible: PropTypes.bool,
projectData: PropTypes.string,
vm: PropTypes.instanceOf(VM)
@@ -83,6 +100,7 @@ const mapStateToProps = state => ({
costumesTabVisible: state.editorTab.activeTabIndex === COSTUMES_TAB_INDEX,
feedbackFormVisible: state.modals.feedbackForm,
importInfoVisible: state.modals.importInfo,
loadingStateVisible: state.modals.loadingProject,
previewInfoVisible: state.modals.previewInfo,
soundsTabVisible: state.editorTab.activeTabIndex === SOUNDS_TAB_INDEX
});
+1 -1
View File
@@ -51,7 +51,7 @@ class ImportModal extends React.Component {
this.setState({inputValue: e.target.value, hasValidationError: false});
}
validate (input) {
const urlMatches = input.match(/^(?:https:\/\/)?scratch\.mit\.edu\/projects\/(\d+)/);
const urlMatches = input.match(/^(?:https?:\/\/)?scratch\.mit\.edu\/projects\/(\d+)/);
if (urlMatches && urlMatches.length > 0) {
return urlMatches[1];
}
+36 -6
View File
@@ -5,6 +5,11 @@ import {connect} from 'react-redux';
import LoadButtonComponent from '../components/load-button/load-button.jsx';
import {
openLoadingProject,
closeLoadingProject
} from '../reducers/modals';
class LoadButton extends React.Component {
constructor (props) {
super(props);
@@ -13,11 +18,24 @@ class LoadButton extends React.Component {
'handleChange',
'handleClick'
]);
this.state = {
loadingError: false,
errorMessage: ''
};
}
handleChange (e) {
this.props.openLoadingState();
// Remove the hash if any (without triggering a hash change event or a reload)
history.replaceState({}, document.title, '.');
const reader = new FileReader();
reader.onload = () => this.props.loadProject(reader.result);
reader.readAsText(e.target.files[0]);
reader.onload = () => this.props.vm.loadProject(reader.result)
.then(() => {
this.props.closeLoadingState();
})
.catch(error => {
this.setState({loadingError: true, errorMessage: error});
});
reader.readAsArrayBuffer(e.target.files[0]);
}
handleClick () {
this.fileInput.click();
@@ -26,8 +44,11 @@ class LoadButton extends React.Component {
this.fileInput = input;
}
render () {
if (this.state.loadingError) throw new Error(`Failed to load project: ${this.state.errorMessage}`);
const {
loadProject, // eslint-disable-line no-unused-vars
closeLoadingState, // eslint-disable-line no-unused-vars
openLoadingState, // eslint-disable-line no-unused-vars
vm, // eslint-disable-line no-unused-vars
...props
} = this.props;
return (
@@ -42,14 +63,23 @@ class LoadButton extends React.Component {
}
LoadButton.propTypes = {
loadProject: PropTypes.func.isRequired
closeLoadingState: PropTypes.func,
openLoadingState: PropTypes.func,
vm: PropTypes.shape({
loadProject: PropTypes.func
})
};
const mapStateToProps = state => ({
loadProject: state.vm.fromJSON.bind(state.vm)
vm: state.vm
});
const mapDispatchToProps = dispatch => ({
closeLoadingState: () => dispatch(closeLoadingProject()),
openLoadingState: () => dispatch(openLoadingProject())
});
export default connect(
mapStateToProps,
() => ({}) // omit dispatch prop
mapDispatchToProps
)(LoadButton);
+2 -1
View File
@@ -59,7 +59,8 @@ const mapStateToProps = (state, {selectedCostumeIndex}) => {
name: costume && costume.name,
rotationCenterX: costume && costume.rotationCenterX,
rotationCenterY: costume && costume.rotationCenterY,
svgId: editingTarget && `${editingTarget}${costume.skinId}`
svgId: editingTarget && `${editingTarget}${costume.skinId}`,
vm: state.vm
};
};
+1 -4
View File
@@ -36,10 +36,7 @@ class PreviewModal extends React.Component {
this.props.onViewProject();
}
supportedBrowser () {
if (platform.name === 'IE') {
return false;
}
return true;
return !['IE', 'Opera', 'Opera Mini', 'Silk', 'Vivaldi'].includes(platform.name);
}
render () {
return (this.supportedBrowser() ?
+7 -5
View File
@@ -73,22 +73,24 @@ class RecordModal extends React.Component {
sampleRate: this.state.sampleRate,
channelData: [clippedSamples]
}).then(wavBuffer => {
const md5 = String(Math.floor(100000 * Math.random()));
const vmSound = {
format: '',
md5: `${md5}.wav`,
dataFormat: 'wav',
name: `recording ${this.props.vm.editingTarget.sprite.sounds.length}`
};
// Load the encoded .wav into the storage cache
// Load the encoded .wav into the storage cache and get resulting
// md5 from storage
const storage = this.props.vm.runtime.storage;
storage.builtinHelper.cache(
const md5 = storage.builtinHelper.cache(
storage.AssetType.Sound,
storage.DataFormat.WAV,
new Uint8Array(wavBuffer),
md5
);
// update vmSound object with md5 property
vmSound.md5 = `${md5}.${vmSound.dataFormat}`;
this.props.vm.addSound(vmSound).then(() => {
this.props.onClose();
this.props.onNewSound();
+19 -17
View File
@@ -15,28 +15,28 @@ class SaveButton extends React.Component {
]);
}
handleClick () {
const json = this.props.saveProjectSb3();
// Download project data into a file - create link element,
// simulate click on it, and then remove it.
const saveLink = document.createElement('a');
document.body.appendChild(saveLink);
const data = new Blob([json], {type: 'text'});
const url = window.URL.createObjectURL(data);
saveLink.href = url;
this.props.vm.saveProjectSb3().then(content => {
const url = window.URL.createObjectURL(content);
// File name: project-DATE-TIME
const date = new Date();
const timestamp = `${date.toLocaleDateString()}-${date.toLocaleTimeString()}`;
saveLink.download = `project-${timestamp}.json`;
saveLink.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(saveLink);
saveLink.href = url;
// TODO user-friendly project name
// File name: project-DATE-TIME
const date = new Date();
const timestamp = `${date.toLocaleDateString()}-${date.toLocaleTimeString()}`;
// TODO change extension to sb3
saveLink.download = `untitled-project-${timestamp}.sb3`;
saveLink.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(saveLink);
});
}
render () {
const {
saveProjectSb3, // eslint-disable-line no-unused-vars
vm, // eslint-disable-line no-unused-vars
...props
} = this.props;
return (
@@ -57,11 +57,13 @@ class SaveButton extends React.Component {
}
SaveButton.propTypes = {
saveProjectSb3: PropTypes.func.isRequired
vm: PropTypes.shape({
saveProjectSb3: PropTypes.func
})
};
const mapStateToProps = state => ({
saveProjectSb3: state.vm.saveProjectSb3.bind(state.vm)
vm: state.vm
});
export default connect(
+8 -7
View File
@@ -89,7 +89,7 @@ class SoundEditor extends React.Component {
}
this.resetState(samples, sampleRate);
this.props.onUpdateSoundBuffer(
this.props.vm.updateSoundBuffer(
this.props.soundIndex,
this.audioBufferPlayer.buffer,
wavBuffer ? new Uint8Array(wavBuffer) : new Uint8Array());
@@ -112,7 +112,7 @@ class SoundEditor extends React.Component {
this.setState({playhead});
}
handleChangeName (name) {
this.props.onRenameSound(this.props.soundIndex, name);
this.props.vm.renameSound(this.props.soundIndex, name);
}
handleActivateTrim () {
if (this.state.trimStart === null && this.state.trimEnd === null) {
@@ -200,12 +200,14 @@ class SoundEditor extends React.Component {
SoundEditor.propTypes = {
name: PropTypes.string.isRequired,
onRenameSound: PropTypes.func.isRequired,
onUpdateSoundBuffer: PropTypes.func.isRequired,
sampleRate: PropTypes.number,
samples: PropTypes.instanceOf(Float32Array),
soundId: PropTypes.string,
soundIndex: PropTypes.number
soundIndex: PropTypes.number,
vm: PropTypes.shape({
updateSoundBuffer: PropTypes.func,
renameSound: PropTypes.func
})
};
const mapStateToProps = (state, {soundIndex}) => {
@@ -219,8 +221,7 @@ const mapStateToProps = (state, {soundIndex}) => {
sampleRate: audioBuffer.sampleRate,
samples: audioBuffer.getChannelData(0),
name: sound.name,
onRenameSound: state.vm.renameSound.bind(state.vm),
onUpdateSoundBuffer: state.vm.updateSoundBuffer.bind(state.vm)
vm: state.vm
};
};
+7 -1
View File
@@ -46,8 +46,14 @@ class SoundTab extends React.Component {
} = nextProps;
const target = editingTarget && sprites[editingTarget] ? sprites[editingTarget] : stage;
if (!target || !target.sounds) {
return;
}
if (target && target.sounds && this.state.selectedSoundIndex > target.sounds.length - 1) {
// If switching editing targets, reset the sound index
if (this.props.editingTarget !== editingTarget) {
this.setState({selectedSoundIndex: 0});
} else if (this.state.selectedSoundIndex > target.sounds.length - 1) {
this.setState({selectedSoundIndex: Math.max(target.sounds.length - 1, 0)});
}
}
+4 -1
View File
@@ -38,7 +38,9 @@ class StageSelector extends React.Component {
handleSurpriseBackdrop () {
// @todo should this not add a backdrop you already have?
const item = backdropLibraryContent[Math.floor(Math.random() * backdropLibraryContent.length)];
this.addBackdropFromLibraryItem(item);
this.addBackdropFromLibraryItem(item).then(() => {
this.props.onActivateTab(COSTUMES_TAB_INDEX);
});
}
handleEmptyBackdrop () {
// @todo this is brittle, will need to be refactored for localized libraries
@@ -83,6 +85,7 @@ const mapStateToProps = (state, {assetId}) => ({
const mapDispatchToProps = dispatch => ({
onNewBackdropClick: e => {
e.preventDefault();
dispatch(activateTab(COSTUMES_TAB_INDEX));
dispatch(openBackdropLibrary());
},
onActivateTab: tabIndex => {
+9 -9
View File
@@ -186,18 +186,18 @@ class Stage extends React.Component {
mouseDown: false,
mouseDownPosition: null
});
const data = {
isDown: false,
x: x - this.rect.left,
y: y - this.rect.top,
canvasWidth: this.rect.width,
canvasHeight: this.rect.height,
wasDragged: this.state.isDragging
};
if (this.state.isDragging) {
this.onStopDrag();
} else {
const data = {
isDown: false,
x: x - this.rect.left,
y: y - this.rect.top,
canvasWidth: this.rect.width,
canvasHeight: this.rect.height
};
this.props.vm.postIOData('mouse', data);
}
this.props.vm.postIOData('mouse', data);
}
onMouseDown (e) {
this.updateRect();
+5 -7
View File
@@ -5,7 +5,6 @@ import {connect} from 'react-redux';
import {
openSpriteLibrary,
closeBackdropLibrary,
closeSpriteLibrary
} from '../reducers/modals';
@@ -75,7 +74,9 @@ class TargetPane extends React.Component {
const emptyItem = spriteLibraryContent.find(item => item.name === 'Empty');
if (emptyItem) {
this.props.vm.addSprite2(JSON.stringify(emptyItem.json)).then(() => {
this.props.onActivateTab(COSTUMES_TAB_INDEX);
setTimeout(() => { // Wait for targets update to propagate before tab switching
this.props.onActivateTab(COSTUMES_TAB_INDEX);
});
});
}
}
@@ -88,6 +89,7 @@ class TargetPane extends React.Component {
render () {
const {
onActivateTab, // eslint-disable-line no-unused-vars
onReceivedBlocks, // eslint-disable-line no-unused-vars
...componentProps
} = this.props;
return (
@@ -132,8 +134,7 @@ const mapStateToProps = state => ({
}, {}),
stage: state.targets.stage,
raiseSprites: state.blockDrag,
spriteLibraryVisible: state.modals.spriteLibrary,
backdropLibraryVisible: state.modals.backdropLibrary
spriteLibraryVisible: state.modals.spriteLibrary
});
const mapDispatchToProps = dispatch => ({
onNewSpriteClick: e => {
@@ -143,9 +144,6 @@ const mapDispatchToProps = dispatch => ({
onRequestCloseSpriteLibrary: () => {
dispatch(closeSpriteLibrary());
},
onRequestCloseBackdropLibrary: () => {
dispatch(closeBackdropLibrary());
},
onActivateTab: tabIndex => {
dispatch(activateTab(tabIndex));
},
+4
View File
@@ -4,6 +4,8 @@ $ui-background-blue: #e8edf1;
$text-primary: #575e75;
$menubar-gray: rgba(0,0,0,0.25);
$motion-primary: #4C97FF;
$motion-tertiary: #3373CC;
$motion-transparent: hsla(215, 100%, 65%, 0.20);
@@ -11,6 +13,8 @@ $motion-transparent: hsla(215, 100%, 65%, 0.20);
$red-primary: #FF661A;
$red-tertiary: #E64D00;
$share-orange: #FFAB19;
$sound-primary: #CF63CF;
$sound-tertiary: #A63FA6;
+128 -1
View File
@@ -1 +1,128 @@
{"targets":[{"id":"`jEk@4|i[#Fk?(8x)AV.","name":"Stage","isStage":true,"x":0,"y":0,"size":100,"direction":90,"draggable":false,"currentCostume":0,"costume":{"name":"backdrop1","bitmapResolution":1,"rotationCenterX":240,"rotationCenterY":180,"skinId":2,"dataFormat":"png","assetId":"739b5e2a2435f6e1ec2993791b423146"},"costumeCount":1,"visible":true,"rotationStyle":"all around","blocks":{},"variables":{"`jEk@4|i[#Fk?(8x)AV.-my variable":{"id":"`jEk@4|i[#Fk?(8x)AV.-my variable","name":"my variable","type":"","isCloud":false,"value":0}},"lists":{},"costumes":[{"name":"backdrop1","bitmapResolution":1,"rotationCenterX":240,"rotationCenterY":180,"skinId":2,"dataFormat":"png","assetId":"739b5e2a2435f6e1ec2993791b423146"}],"sounds":[{"name":"pop","format":"","rate":11025,"sampleCount":258,"soundID":1,"md5":"83a9787d4cb6f3b7632b4ddfebf74367.wav","data":null,"dataFormat":"wav","assetId":"83a9787d4cb6f3b7632b4ddfebf74367","soundId":"p=i?*Zt*I]@]x_*V`mut"}]},{"id":"9xJ@2eKXvx:/*Q^3Rib#","name":"Sprite1","isStage":false,"x":0,"y":0,"size":100,"direction":90,"draggable":false,"currentCostume":0,"costume":{"name":"costume1","bitmapResolution":1,"rotationCenterX":47,"rotationCenterY":55,"skinId":0,"dataFormat":"svg","assetId":"09dc888b0b7df19f70d81588ae73420e"},"costumeCount":2,"visible":true,"rotationStyle":"all around","blocks":{},"variables":{},"lists":{},"costumes":[{"name":"costume1","bitmapResolution":1,"rotationCenterX":47,"rotationCenterY":55,"skinId":0,"dataFormat":"svg","assetId":"09dc888b0b7df19f70d81588ae73420e"},{"name":"costume2","bitmapResolution":1,"rotationCenterX":47,"rotationCenterY":55,"skinId":1,"dataFormat":"svg","assetId":"3696356a03a8d938318876a593572843"}],"sounds":[{"name":"Meow","format":"","rate":22050,"sampleCount":18688,"soundID":0,"md5":"83c36d806dc92327b9e7049a565c6bff.wav","data":null,"dataFormat":"wav","assetId":"83c36d806dc92327b9e7049a565c6bff","soundId":"]z6@jLeJ2W%gr/eA1HB+"}]}],"meta":{"semver":"3.0.0","vm":"0.1.0","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"}}
{
"targets": [
{
"id": "`jEk@4|i[#Fk?(8x)AV.",
"name": "Stage",
"isStage": true,
"x": 0,
"y": 0,
"size": 100,
"direction": 90,
"draggable": false,
"currentCostume": 0,
"costume": {
"name": "backdrop1",
"bitmapResolution": 1,
"rotationCenterX": 240,
"rotationCenterY": 180,
"skinId": 2,
"dataFormat": "png",
"assetId": "739b5e2a2435f6e1ec2993791b423146"
},
"costumeCount": 1,
"visible": true,
"rotationStyle": "all around",
"blocks": {},
"variables": {
"`jEk@4|i[#Fk?(8x)AV.-my variable": {
"id": "`jEk@4|i[#Fk?(8x)AV.-my variable",
"name": "my variable",
"type": "",
"isCloud": false,
"value": 0
}
},
"lists": {},
"costumes": [
{
"name": "backdrop1",
"bitmapResolution": 1,
"rotationCenterX": 240,
"rotationCenterY": 180,
"skinId": 2,
"dataFormat": "png",
"assetId": "739b5e2a2435f6e1ec2993791b423146"
}
],
"sounds": [
{
"name": "pop",
"format": "",
"rate": 11025,
"sampleCount": 258,
"soundID": 1,
"md5ext": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"data": null,
"dataFormat": "wav",
"assetId": "83a9787d4cb6f3b7632b4ddfebf74367",
"soundId": "p=i?*Zt*I]@]x_*V`mut"
}
]
},
{
"id": "9xJ@2eKXvx:/*Q^3Rib#",
"name": "Sprite1",
"isStage": false,
"x": 0,
"y": 0,
"size": 100,
"direction": 90,
"draggable": false,
"currentCostume": 0,
"costume": {
"name": "costume1",
"bitmapResolution": 1,
"rotationCenterX": 47,
"rotationCenterY": 55,
"skinId": 0,
"dataFormat": "svg",
"assetId": "09dc888b0b7df19f70d81588ae73420e"
},
"costumeCount": 2,
"visible": true,
"rotationStyle": "all around",
"blocks": {},
"variables": {},
"lists": {},
"costumes": [
{
"name": "costume1",
"bitmapResolution": 1,
"rotationCenterX": 47,
"rotationCenterY": 55,
"skinId": 0,
"dataFormat": "svg",
"assetId": "09dc888b0b7df19f70d81588ae73420e"
},
{
"name": "costume2",
"bitmapResolution": 1,
"rotationCenterX": 47,
"rotationCenterY": 55,
"skinId": 1,
"dataFormat": "svg",
"assetId": "3696356a03a8d938318876a593572843"
}
],
"sounds": [
{
"name": "Meow",
"format": "",
"rate": 22050,
"sampleCount": 18688,
"soundID": 0,
"md5ext": "83c36d806dc92327b9e7049a565c6bff.wav",
"data": null,
"dataFormat": "wav",
"assetId": "83c36d806dc92327b9e7049a565c6bff",
"soundId": "]z6@jLeJ2W%gr/eA1HB+"
}
]
}
],
"meta": {
"semver": "3.0.0",
"vm": "0.1.0",
"agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"
}
}
+184 -206
View File
@@ -615,6 +615,17 @@
1
]
},
{
"name": "Cat1",
"md5": "09dc888b0b7df19f70d81588ae73420e.svg",
"type": "costume",
"tags": [],
"info": [
47,
55,
1
]
},
{
"name": "Cat1 Flying-a",
"md5": "1e81725d2d2c7de4a2dd4a145198a43c.svg",
@@ -637,6 +648,17 @@
1
]
},
{
"name": "Cat2",
"md5": "3696356a03a8d938318876a593572843.svg",
"type": "costume",
"tags": [],
"info": [
47,
55,
1
]
},
{
"name": "Cloud-a",
"md5": "c7d7de8e29179407f03b054fa640f4d0.svg",
@@ -681,28 +703,6 @@
1
]
},
{
"name": "Costume1",
"md5": "09dc888b0b7df19f70d81588ae73420e.svg",
"type": "costume",
"tags": [],
"info": [
47,
55,
1
]
},
{
"name": "Costume2",
"md5": "3696356a03a8d938318876a593572843.svg",
"type": "costume",
"tags": [],
"info": [
47,
55,
1
]
},
{
"name": "Crab-a",
"md5": "114249a5660f7948663d95de575cfd8d.svg",
@@ -1132,17 +1132,6 @@
1
]
},
{
"name": "Drum-c",
"md5": "50cf928f06481ff823e18e70c01df807.svg",
"type": "costume",
"tags": [],
"info": [
43,
60,
1
]
},
{
"name": "Drum-cymbal-a",
"md5": "d6d41862fda966df1455d2dbff5e1988.svg",
@@ -1165,17 +1154,6 @@
1
]
},
{
"name": "Drum-cymbal-c",
"md5": "0e85f690e8eaf153ae20cbbbb88ca60c.svg",
"type": "costume",
"tags": [],
"info": [
30,
74,
1
]
},
{
"name": "Drum-highhat-a",
"md5": "81fb79151a63cb096258607451cc2cf5.svg",
@@ -1198,17 +1176,6 @@
1
]
},
{
"name": "Drum-highhat-c",
"md5": "c6f2467a5226f7d372d15669c5099a41.svg",
"type": "costume",
"tags": [],
"info": [
33,
73,
1
]
},
{
"name": "Drum-kit",
"md5": "131d040d86ecea62ccd175a8709c7866.svg",
@@ -1231,25 +1198,14 @@
1
]
},
{
"name": "Drum-kit-c",
"md5": "4ca5c6eee4d907b98fb62340bd4a2cde.svg",
"type": "costume",
"tags": [],
"info": [
58,
78,
1
]
},
{
"name": "Drum-snare-a",
"md5": "31a81bb560abf30cbc44bcdd581d5ccc.svg",
"md5": "b0255be93e3c8be6ac687f4199a25c4b.svg",
"type": "costume",
"tags": [],
"info": [
40,
69,
23,
50,
1
]
},
@@ -1264,17 +1220,6 @@
1
]
},
{
"name": "Drum-snare-c",
"md5": "878ea646cbbd2a9e24fdeb8d98c3e24f.svg",
"type": "costume",
"tags": [],
"info": [
40,
69,
1
]
},
{
"name": "Duck",
"md5": "c3baf7eedfbdac8cd1e4f1f1f779dc0c.svg",
@@ -1649,17 +1594,6 @@
1
]
},
{
"name": "Guitar-c",
"md5": "5cfe9faacb98d35a702cfa633967a5b5.svg",
"type": "costume",
"tags": [],
"info": [
47,
83,
1
]
},
{
"name": "Guitar-electric1-a",
"md5": "b2b469b9d11fd23bdd671eab94dc58ff.svg",
@@ -1682,17 +1616,6 @@
1
]
},
{
"name": "Guitar-electric1-c",
"md5": "4cb069d2a290c0a153f196de725d357c.svg",
"type": "costume",
"tags": [],
"info": [
42,
85,
1
]
},
{
"name": "Guitar-electric2-a",
"md5": "1fc433b89038f9e16092c9f4d7514cca.svg",
@@ -1715,17 +1638,6 @@
1
]
},
{
"name": "Guitar-electric2-c",
"md5": "7f5f8b6d772657566e3dee24c9a9c538.svg",
"type": "costume",
"tags": [],
"info": [
38,
94,
1
]
},
{
"name": "Hedgehog-a",
"md5": "32416e6b2ef8e45fb5fd10778c1b9a9f.svg",
@@ -1913,61 +1825,6 @@
1
]
},
{
"name": "Jez-b",
"md5": "f1e74f3c02333e9e2068e8baf4e77aa0.svg",
"type": "costume",
"tags": [],
"info": [
67,
95,
1
]
},
{
"name": "Jez-c",
"md5": "e2482cf509c312935f08be0e2e2c9d84.svg",
"type": "costume",
"tags": [],
"info": [
67,
95,
1
]
},
{
"name": "Jez-d",
"md5": "569e736b519199efddfbae2572f7e92b.svg",
"type": "costume",
"tags": [],
"info": [
67,
95,
1
]
},
{
"name": "Jez-e",
"md5": "2261bed0f2cc819def17969158297b4f.svg",
"type": "costume",
"tags": [],
"info": [
77,
95,
1
]
},
{
"name": "Jez-f",
"md5": "d7f44adb3dc7906b9dfb3599a028e0d6.svg",
"type": "costume",
"tags": [],
"info": [
62,
94,
1
]
},
{
"name": "Jordyn-a",
"md5": "8dd2a2abbb8e639da8576b6e72ef9e59.svg",
@@ -2034,17 +1891,6 @@
1
]
},
{
"name": "Keyboard-c",
"md5": "4ee5e7c6d0463d9b50e0c593e70e1e31.svg",
"type": "costume",
"tags": [],
"info": [
72,
68,
1
]
},
{
"name": "Kiran-a",
"md5": "9de23c4a7a7fbb67136b539241346854.svg",
@@ -2056,6 +1902,61 @@
1
]
},
{
"name": "Kiran-b",
"md5": "f1e74f3c02333e9e2068e8baf4e77aa0.svg",
"type": "costume",
"tags": [],
"info": [
67,
95,
1
]
},
{
"name": "Kiran-c",
"md5": "e2482cf509c312935f08be0e2e2c9d84.svg",
"type": "costume",
"tags": [],
"info": [
67,
95,
1
]
},
{
"name": "Kiran-d",
"md5": "569e736b519199efddfbae2572f7e92b.svg",
"type": "costume",
"tags": [],
"info": [
67,
95,
1
]
},
{
"name": "Kiran-e",
"md5": "2261bed0f2cc819def17969158297b4f.svg",
"type": "costume",
"tags": [],
"info": [
77,
95,
1
]
},
{
"name": "Kiran-f",
"md5": "d7f44adb3dc7906b9dfb3599a028e0d6.svg",
"type": "costume",
"tags": [],
"info": [
62,
94,
1
]
},
{
"name": "Knight",
"md5": "f2c5e8bc24d001b81566879dbf2f1a13.svg",
@@ -2199,17 +2100,6 @@
1
]
},
{
"name": "Microphone-c",
"md5": "021d6da78b7bda374da4bdb50d4cbc4f.svg",
"type": "costume",
"tags": [],
"info": [
40,
88,
1
]
},
{
"name": "Milk-a",
"md5": "e6a7964bc4ea38c79a5a31d6ddfb5ba9.svg",
@@ -2541,7 +2431,7 @@
]
},
{
"name": "Penguin1",
"name": "Penguin1-a",
"md5": "c17d9e4bdb59c574e0c34aa70af516da.svg",
"type": "costume",
"tags": [],
@@ -2551,6 +2441,61 @@
1
]
},
{
"name": "Penguin1-b",
"md5": "35fec7aa5f60cca945fe0615413f1f08.svg",
"type": "costume",
"tags": [],
"info": [
48,
62,
1
]
},
{
"name": "Penguin1-c",
"md5": "18fa51a64ebd5518f0c5c465525346e5.svg",
"type": "costume",
"tags": [],
"info": [
48,
61,
1
]
},
{
"name": "Penguin2-a",
"md5": "eaaaa7068e78a51d73ba437f1ec5763e.svg",
"type": "costume",
"tags": [],
"info": [
49,
79,
1
]
},
{
"name": "Penguin2-b",
"md5": "5a80f4b2fd20d43e4f7cb4189c08d99c.svg",
"type": "costume",
"tags": [],
"info": [
45,
79,
1
]
},
{
"name": "Penguin2-c",
"md5": "394e79f5f9a462064ece2a9a6606a07d.svg",
"type": "costume",
"tags": [],
"info": [
50,
78,
1
]
},
{
"name": "Pico-a",
"md5": "0579fe60bb3717c49dfd7743caa84ada.svg",
@@ -2926,13 +2871,35 @@
]
},
{
"name": "Saxophone-c",
"md5": "29751826f768bc1568092f267525ae8b.svg",
"name": "Shark-a ",
"md5": "7c0a907eae79462f69f8e2af8e7df828.svg",
"type": "costume",
"tags": [],
"info": [
47,
80,
75,
75,
1
]
},
{
"name": "Shark-b ",
"md5": "cff9ae87a93294693a0650b38a7a33d2.svg",
"type": "costume",
"tags": [],
"info": [
75,
75,
1
]
},
{
"name": "Shark-c ",
"md5": "afeae3f998598424f7c50918507f6ce6.svg",
"type": "costume",
"tags": [],
"info": [
77,
37,
1
]
},
@@ -3057,6 +3024,28 @@
1
]
},
{
"name": "Starfish-a",
"md5": "3d1101bbc24ae292a36356af325f660c.svg",
"type": "costume",
"tags": [],
"info": [
75,
75,
1
]
},
{
"name": "Starfish-b ",
"md5": "ad8007f4e63693984d4adc466ffa3ad2.svg",
"type": "costume",
"tags": [],
"info": [
53,
60,
1
]
},
{
"name": "Strawberry-a",
"md5": "734556fb8e14740f2cbc971238b71d47.svg",
@@ -3266,17 +3255,6 @@
1
]
},
{
"name": "Trumpet-c",
"md5": "680dd004c24690af1e95c4beb22cd615.svg",
"type": "costume",
"tags": [],
"info": [
37,
73,
1
]
},
{
"name": "Unicorn",
"md5": "a04def38351e7fd805226345cac4fbfe.svg",
+10 -17
View File
@@ -470,10 +470,10 @@
},
{
"name": "Cheer",
"md5": "4b36eebf22be4667fc2f15b78c805b4c.wav",
"sampleCount": 62528,
"md5": "170e05c29d50918ae0b482c2955768c0.wav",
"sampleCount": 108864,
"rate": 22050,
"format": ""
"format": "adpcm"
},
{
"name": "Chirp",
@@ -553,19 +553,12 @@
"format": ""
},
{
"name": "Computer Beeps1",
"name": "Computer Beep2",
"md5": "1da43f6d52d0615da8a250e28100a80d.wav",
"sampleCount": 19200,
"rate": 11025,
"format": ""
},
{
"name": "Computer Beeps2",
"md5": "28c76b6bebd04be1383fe9ba4933d263.wav",
"sampleCount": 9536,
"rate": 11025,
"format": ""
},
{
"name": "Connect",
"md5": "9aad12085708ccd279297d4bea9c5ae0.wav",
@@ -1842,10 +1835,10 @@
},
{
"name": "Screech",
"md5": "3676f478e5e3496034cf100d239160df.wav",
"sampleCount": 28928,
"rate": 11025,
"format": ""
"md5": "10644c5cc83a9a2dd3ab466deb0eb03d.wav",
"sampleCount": 12907,
"rate": 22050,
"format": "adpcm"
},
{
"name": "Seagulls",
@@ -2269,8 +2262,8 @@
},
{
"name": "Water Drop",
"md5": "aa488de9e2c871e9d4faecd246ed737a.wav",
"sampleCount": 8136,
"md5": "e133e625fd367d269e76964d4b722fc2.wav",
"sampleCount": 15131,
"rate": 22050,
"format": "adpcm"
},
+314 -214
View File
@@ -62,7 +62,7 @@
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 10,
"indexInLibrary": 11,
"visible": true,
"spriteInfo": {}
}
@@ -456,7 +456,7 @@
}
},
{
"name": "Bat3",
"name": "Bat2",
"md5": "647d4bd53163f94a7dabf623ccab7fd3.svg",
"type": "sprite",
"tags": [],
@@ -466,7 +466,7 @@
1
],
"json": {
"objName": "Bat3",
"objName": "Bat2",
"sounds": [
{
"soundName": "pop",
@@ -502,7 +502,7 @@
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 12,
"indexInLibrary": 10,
"visible": true,
"spriteInfo": {}
}
@@ -546,7 +546,7 @@
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 11,
"indexInLibrary": 12,
"visible": true,
"spriteInfo": {}
}
@@ -1169,7 +1169,7 @@
"objName": "Cake",
"sounds": [
{
"soundName": "birthday song",
"soundName": "birthday",
"soundID": -1,
"md5": "89691587a169d935a58c48c3d4e78534.wav",
"sampleCount": 161408,
@@ -1299,7 +1299,7 @@
],
"costumes": [
{
"costumeName": "costume1",
"costumeName": "cat1",
"baseLayerID": -1,
"baseLayerMD5": "09dc888b0b7df19f70d81588ae73420e.svg",
"bitmapResolution": 1,
@@ -1307,7 +1307,7 @@
"rotationCenterY": 55
},
{
"costumeName": "costume2",
"costumeName": "cat2",
"baseLayerID": -1,
"baseLayerMD5": "3696356a03a8d938318876a593572843.svg",
"bitmapResolution": 1,
@@ -1315,7 +1315,7 @@
"rotationCenterY": 55
}
],
"currentCostumeIndex": 0,
"currentCostumeIndex": 1,
"scratchX": 0,
"scratchY": 0,
"scale": 1,
@@ -2166,7 +2166,7 @@
"tags": [],
"info": [
0,
3,
2,
2
],
"json": {
@@ -2205,14 +2205,6 @@
"bitmapResolution": 1,
"rotationCenterX": 43,
"rotationCenterY": 60
},
{
"costumeName": "drum-c",
"baseLayerID": -1,
"baseLayerMD5": "50cf928f06481ff823e18e70c01df807.svg",
"bitmapResolution": 1,
"rotationCenterX": 43,
"rotationCenterY": 60
}
],
"currentCostumeIndex": 0,
@@ -2234,7 +2226,7 @@
"tags": [],
"info": [
0,
3,
2,
5
],
"json": {
@@ -2297,14 +2289,6 @@
"bitmapResolution": 1,
"rotationCenterX": 58,
"rotationCenterY": 78
},
{
"costumeName": "drum-kit-c",
"baseLayerID": -1,
"baseLayerMD5": "4ca5c6eee4d907b98fb62340bd4a2cde.svg",
"bitmapResolution": 1,
"rotationCenterX": 58,
"rotationCenterY": 78
}
],
"currentCostumeIndex": 0,
@@ -2326,7 +2310,7 @@
"tags": [],
"info": [
0,
3,
2,
4
],
"json": {
@@ -2381,14 +2365,6 @@
"bitmapResolution": 1,
"rotationCenterX": 30,
"rotationCenterY": 74
},
{
"costumeName": "drum-cymbal-c",
"baseLayerID": -1,
"baseLayerMD5": "0e85f690e8eaf153ae20cbbbb88ca60c.svg",
"bitmapResolution": 1,
"rotationCenterX": 30,
"rotationCenterY": 74
}
],
"currentCostumeIndex": 0,
@@ -2410,7 +2386,7 @@
"tags": [],
"info": [
0,
3,
2,
1
],
"json": {
@@ -2441,14 +2417,6 @@
"bitmapResolution": 1,
"rotationCenterX": 33,
"rotationCenterY": 73
},
{
"costumeName": "drum-highhat-c",
"baseLayerID": -1,
"baseLayerMD5": "c6f2467a5226f7d372d15669c5099a41.svg",
"bitmapResolution": 1,
"rotationCenterX": 33,
"rotationCenterY": 73
}
],
"currentCostumeIndex": 0,
@@ -2465,12 +2433,12 @@
},
{
"name": "Drum-snare",
"md5": "31a81bb560abf30cbc44bcdd581d5ccc.svg",
"md5": "b0255be93e3c8be6ac687f4199a25c4b.svg",
"type": "sprite",
"tags": [],
"info": [
0,
3,
2,
3
],
"json": {
@@ -2505,29 +2473,21 @@
{
"costumeName": "drum-snare-a",
"baseLayerID": -1,
"baseLayerMD5": "31a81bb560abf30cbc44bcdd581d5ccc.svg",
"baseLayerMD5": "b0255be93e3c8be6ac687f4199a25c4b.svg",
"bitmapResolution": 1,
"rotationCenterX": 40,
"rotationCenterY": 69
"rotationCenterX": 23,
"rotationCenterY": 50
},
{
"costumeName": "drum-snare-b",
"baseLayerID": 0,
"baseLayerID": -1,
"baseLayerMD5": "f6d2f2a6e1055dab6262336625ddf652.svg",
"bitmapResolution": 1,
"rotationCenterX": 36,
"rotationCenterY": 66
},
{
"costumeName": "drum-snare-c",
"baseLayerID": -1,
"baseLayerMD5": "878ea646cbbd2a9e24fdeb8d98c3e24f.svg",
"bitmapResolution": 1,
"rotationCenterX": 40,
"rotationCenterY": 69
}
],
"currentCostumeIndex": 1,
"currentCostumeIndex": 0,
"scratchX": 45,
"scratchY": -33,
"scale": 1,
@@ -3234,7 +3194,7 @@
"tags": [],
"info": [
0,
3,
2,
8
],
"json": {
@@ -3321,14 +3281,6 @@
"bitmapResolution": 1,
"rotationCenterX": 47,
"rotationCenterY": 83
},
{
"costumeName": "guitar-c",
"baseLayerID": -1,
"baseLayerMD5": "5cfe9faacb98d35a702cfa633967a5b5.svg",
"bitmapResolution": 1,
"rotationCenterX": 47,
"rotationCenterY": 83
}
],
"currentCostumeIndex": 0,
@@ -3350,7 +3302,7 @@
"tags": [],
"info": [
0,
3,
2,
8
],
"json": {
@@ -3437,14 +3389,6 @@
"bitmapResolution": 1,
"rotationCenterX": 38,
"rotationCenterY": 94
},
{
"costumeName": "guitar-electric2-c",
"baseLayerID": -1,
"baseLayerMD5": "7f5f8b6d772657566e3dee24c9a9c538.svg",
"bitmapResolution": 1,
"rotationCenterX": 38,
"rotationCenterY": 94
}
],
"currentCostumeIndex": 0,
@@ -3466,7 +3410,7 @@
"tags": [],
"info": [
0,
3,
2,
8
],
"json": {
@@ -3553,14 +3497,6 @@
"bitmapResolution": 1,
"rotationCenterX": 42,
"rotationCenterY": 85
},
{
"costumeName": "guitar-electric1-c",
"baseLayerID": -1,
"baseLayerMD5": "4cb069d2a290c0a153f196de725d357c.svg",
"bitmapResolution": 1,
"rotationCenterX": 42,
"rotationCenterY": 85
}
],
"currentCostumeIndex": 0,
@@ -3711,17 +3647,25 @@
"info": [
0,
2,
1
2
],
"json": {
"objName": "Horse1",
"sounds": [
{
"soundName": "meow",
"soundName": "horse",
"soundID": -1,
"md5": "83c36d806dc92327b9e7049a565c6bff.wav",
"sampleCount": 18688,
"rate": 22050,
"md5": "45ffcf97ee2edca0199ff5aa71a5b72e.wav",
"sampleCount": 14464,
"rate": 11025,
"format": ""
},
{
"soundName": "horse gallop",
"soundID": -1,
"md5": "058a34b5fb8b57178b5322d994b6b8c8.wav",
"sampleCount": 38336,
"rate": 11025,
"format": ""
}
],
@@ -3891,90 +3835,6 @@
"spriteInfo": {}
}
},
{
"name": "Jez",
"md5": "9de23c4a7a7fbb67136b539241346854.svg",
"type": "sprite",
"tags": [],
"info": [
0,
6,
1
],
"json": {
"objName": "jez",
"sounds": [
{
"soundName": "pop",
"soundID": -1,
"md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"sampleCount": 258,
"rate": 11025,
"format": ""
}
],
"costumes": [
{
"costumeName": "kiran-a",
"baseLayerID": -1,
"baseLayerMD5": "9de23c4a7a7fbb67136b539241346854.svg",
"bitmapResolution": 1,
"rotationCenterX": 67,
"rotationCenterY": 95
},
{
"costumeName": "jez-b",
"baseLayerID": -1,
"baseLayerMD5": "f1e74f3c02333e9e2068e8baf4e77aa0.svg",
"bitmapResolution": 1,
"rotationCenterX": 67,
"rotationCenterY": 95
},
{
"costumeName": "jez-c",
"baseLayerID": -1,
"baseLayerMD5": "e2482cf509c312935f08be0e2e2c9d84.svg",
"bitmapResolution": 1,
"rotationCenterX": 67,
"rotationCenterY": 95
},
{
"costumeName": "jez-d",
"baseLayerID": -1,
"baseLayerMD5": "569e736b519199efddfbae2572f7e92b.svg",
"bitmapResolution": 1,
"rotationCenterX": 67,
"rotationCenterY": 95
},
{
"costumeName": "jez-e",
"baseLayerID": -1,
"baseLayerMD5": "2261bed0f2cc819def17969158297b4f.svg",
"bitmapResolution": 1,
"rotationCenterX": 77,
"rotationCenterY": 95
},
{
"costumeName": "jez-f",
"baseLayerID": -1,
"baseLayerMD5": "d7f44adb3dc7906b9dfb3599a028e0d6.svg",
"bitmapResolution": 1,
"rotationCenterX": 62,
"rotationCenterY": 94
}
],
"currentCostumeIndex": 0,
"scratchX": 57,
"scratchY": -42,
"scale": 0.8,
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 3,
"visible": true,
"spriteInfo": {}
}
},
{
"name": "Jordyn",
"md5": "8dd2a2abbb8e639da8576b6e72ef9e59.svg",
@@ -4050,7 +3910,7 @@
"tags": [],
"info": [
0,
3,
2,
8
],
"json": {
@@ -4137,14 +3997,6 @@
"bitmapResolution": 1,
"rotationCenterX": 72,
"rotationCenterY": 68
},
{
"costumeName": "keyboard-c",
"baseLayerID": -1,
"baseLayerMD5": "4ee5e7c6d0463d9b50e0c593e70e1e31.svg",
"bitmapResolution": 1,
"rotationCenterX": 72,
"rotationCenterY": 68
}
],
"currentCostumeIndex": 0,
@@ -4159,6 +4011,90 @@
"spriteInfo": {}
}
},
{
"name": "Kiran",
"md5": "9de23c4a7a7fbb67136b539241346854.svg",
"type": "sprite",
"tags": [],
"info": [
0,
6,
1
],
"json": {
"objName": "kiran",
"sounds": [
{
"soundName": "pop",
"soundID": -1,
"md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"sampleCount": 258,
"rate": 11025,
"format": ""
}
],
"costumes": [
{
"costumeName": "kiran-a",
"baseLayerID": -1,
"baseLayerMD5": "9de23c4a7a7fbb67136b539241346854.svg",
"bitmapResolution": 1,
"rotationCenterX": 67,
"rotationCenterY": 95
},
{
"costumeName": "kiran-b",
"baseLayerID": -1,
"baseLayerMD5": "f1e74f3c02333e9e2068e8baf4e77aa0.svg",
"bitmapResolution": 1,
"rotationCenterX": 67,
"rotationCenterY": 95
},
{
"costumeName": "kiran-c",
"baseLayerID": -1,
"baseLayerMD5": "e2482cf509c312935f08be0e2e2c9d84.svg",
"bitmapResolution": 1,
"rotationCenterX": 67,
"rotationCenterY": 95
},
{
"costumeName": "kiran-d",
"baseLayerID": -1,
"baseLayerMD5": "569e736b519199efddfbae2572f7e92b.svg",
"bitmapResolution": 1,
"rotationCenterX": 67,
"rotationCenterY": 95
},
{
"costumeName": "kiran-e",
"baseLayerID": -1,
"baseLayerMD5": "2261bed0f2cc819def17969158297b4f.svg",
"bitmapResolution": 1,
"rotationCenterX": 77,
"rotationCenterY": 95
},
{
"costumeName": "kiran-f",
"baseLayerID": -1,
"baseLayerMD5": "d7f44adb3dc7906b9dfb3599a028e0d6.svg",
"bitmapResolution": 1,
"rotationCenterX": 62,
"rotationCenterY": 94
}
],
"currentCostumeIndex": 0,
"scratchX": 57,
"scratchY": -42,
"scale": 0.8,
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 3,
"visible": true,
"spriteInfo": {}
}
},
{
"name": "Knight",
"md5": "f2c5e8bc24d001b81566879dbf2f1a13.svg",
@@ -4434,7 +4370,7 @@
"tags": [],
"info": [
0,
3,
2,
9
],
"json": {
@@ -4529,14 +4465,6 @@
"bitmapResolution": 1,
"rotationCenterX": 40,
"rotationCenterY": 88
},
{
"costumeName": "microphone-c",
"baseLayerID": -1,
"baseLayerMD5": "021d6da78b7bda374da4bdb50d4cbc4f.svg",
"bitmapResolution": 1,
"rotationCenterX": 40,
"rotationCenterY": 88
}
],
"currentCostumeIndex": 0,
@@ -5086,7 +5014,7 @@
"tags": [],
"info": [
0,
1,
3,
1
],
"json": {
@@ -5103,12 +5031,28 @@
],
"costumes": [
{
"costumeName": "penguin1",
"costumeName": "penguin1-a",
"baseLayerID": -1,
"baseLayerMD5": "c17d9e4bdb59c574e0c34aa70af516da.svg",
"bitmapResolution": 1,
"rotationCenterX": 54,
"rotationCenterY": 61
},
{
"costumeName": "penguin1-b",
"baseLayerID": -1,
"baseLayerMD5": "35fec7aa5f60cca945fe0615413f1f08.svg",
"bitmapResolution": 1,
"rotationCenterX": 48,
"rotationCenterY": 62
},
{
"costumeName": "penguin1-c",
"baseLayerID": -1,
"baseLayerMD5": "18fa51a64ebd5518f0c5c465525346e5.svg",
"bitmapResolution": 1,
"rotationCenterX": 48,
"rotationCenterY": 61
}
],
"currentCostumeIndex": 0,
@@ -5123,6 +5067,66 @@
"spriteInfo": {}
}
},
{
"name": "Penguin2",
"md5": "eaaaa7068e78a51d73ba437f1ec5763e.svg",
"type": "sprite",
"tags": [],
"info": [
0,
3,
1
],
"json": {
"objName": "Penguin2",
"sounds": [
{
"soundName": "pop",
"soundID": -1,
"md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"sampleCount": 258,
"rate": 11025,
"format": ""
}
],
"costumes": [
{
"costumeName": "penguin2-a",
"baseLayerID": -1,
"baseLayerMD5": "eaaaa7068e78a51d73ba437f1ec5763e.svg",
"bitmapResolution": 1,
"rotationCenterX": 49,
"rotationCenterY": 79
},
{
"costumeName": "penguin2-b",
"baseLayerID": -1,
"baseLayerMD5": "5a80f4b2fd20d43e4f7cb4189c08d99c.svg",
"bitmapResolution": 1,
"rotationCenterX": 45,
"rotationCenterY": 79
},
{
"costumeName": "penguin2-c",
"baseLayerID": -1,
"baseLayerMD5": "394e79f5f9a462064ece2a9a6606a07d.svg",
"bitmapResolution": 1,
"rotationCenterX": 50,
"rotationCenterY": 78
}
],
"currentCostumeIndex": 0,
"scratchX": 95,
"scratchY": 44,
"scale": 1,
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 62,
"visible": true,
"spriteInfo": {}
}
},
{
"name": "Pico",
"md5": "0579fe60bb3717c49dfd7743caa84ada.svg",
@@ -5682,7 +5686,7 @@
"tags": [],
"info": [
0,
3,
2,
8
],
"json": {
@@ -5769,14 +5773,6 @@
"bitmapResolution": 1,
"rotationCenterX": 47,
"rotationCenterY": 80
},
{
"costumeName": "saxophone-c",
"baseLayerID": -1,
"baseLayerMD5": "29751826f768bc1568092f267525ae8b.svg",
"bitmapResolution": 1,
"rotationCenterX": 47,
"rotationCenterY": 80
}
],
"currentCostumeIndex": 0,
@@ -5791,6 +5787,66 @@
"spriteInfo": {}
}
},
{
"name": "Shark",
"md5": "7c0a907eae79462f69f8e2af8e7df828.svg",
"type": "sprite",
"tags": [],
"info": [
0,
3,
1
],
"json": {
"objName": "Shark",
"sounds": [
{
"soundName": "pop",
"soundID": -1,
"md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"sampleCount": 258,
"rate": 11025,
"format": ""
}
],
"costumes": [
{
"costumeName": "shark-a ",
"baseLayerID": -1,
"baseLayerMD5": "7c0a907eae79462f69f8e2af8e7df828.svg",
"bitmapResolution": 1,
"rotationCenterX": 75,
"rotationCenterY": 75
},
{
"costumeName": "shark-b ",
"baseLayerID": -1,
"baseLayerMD5": "cff9ae87a93294693a0650b38a7a33d2.svg",
"bitmapResolution": 1,
"rotationCenterX": 75,
"rotationCenterY": 75
},
{
"costumeName": "shark-c ",
"baseLayerID": -1,
"baseLayerMD5": "afeae3f998598424f7c50918507f6ce6.svg",
"bitmapResolution": 1,
"rotationCenterX": 77,
"rotationCenterY": 37
}
],
"currentCostumeIndex": 0,
"scratchX": 41,
"scratchY": -15,
"scale": 1,
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 63,
"visible": true,
"spriteInfo": {}
}
},
{
"name": "Snake",
"md5": "4d06e12d90479461303d828f0970f2d4.svg",
@@ -6359,6 +6415,58 @@
"spriteInfo": {}
}
},
{
"name": "Starfish",
"md5": "3d1101bbc24ae292a36356af325f660c.svg",
"type": "sprite",
"tags": [],
"info": [
0,
2,
1
],
"json": {
"objName": "Starfish",
"sounds": [
{
"soundName": "pop",
"soundID": -1,
"md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"sampleCount": 258,
"rate": 11025,
"format": ""
}
],
"costumes": [
{
"costumeName": "starfish-a",
"baseLayerID": -1,
"baseLayerMD5": "3d1101bbc24ae292a36356af325f660c.svg",
"bitmapResolution": 1,
"rotationCenterX": 75,
"rotationCenterY": 75
},
{
"costumeName": "starfish-b ",
"baseLayerID": -1,
"baseLayerMD5": "ad8007f4e63693984d4adc466ffa3ad2.svg",
"bitmapResolution": 1,
"rotationCenterX": 53,
"rotationCenterY": 60
}
],
"currentCostumeIndex": 1,
"scratchX": -37,
"scratchY": 38,
"scale": 1,
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 64,
"visible": true,
"spriteInfo": {}
}
},
{
"name": "Strawberry",
"md5": "734556fb8e14740f2cbc971238b71d47.svg",
@@ -6646,7 +6754,7 @@
"tags": [],
"info": [
0,
3,
2,
8
],
"json": {
@@ -6733,14 +6841,6 @@
"bitmapResolution": 1,
"rotationCenterX": 37,
"rotationCenterY": 73
},
{
"costumeName": "trumpet-c",
"baseLayerID": -1,
"baseLayerMD5": "680dd004c24690af1e95c4beb22cd615.svg",
"bitmapResolution": 1,
"rotationCenterX": 37,
"rotationCenterY": 73
}
],
"currentCostumeIndex": 0,
+14 -7
View File
@@ -234,10 +234,10 @@ const looks = function (isStage, targetId) {
</block>
<block type="looks_cleargraphiceffects"/>
${blockSeparator}
<block type="looks_show"/>
<block type="looks_hide"/>
${blockSeparator}
${isStage ? '' : `
<block type="looks_show"/>
<block type="looks_hide"/>
${blockSeparator}
<block type="looks_gotofrontback"/>
<block type="looks_goforwardbackwardlayers">
<value name="NUM">
@@ -246,7 +246,6 @@ const looks = function (isStage, targetId) {
</shadow>
</value>
</block>
${blockSeparator}
`}
${isStage ? `
<block id="backdropnumbername" type="looks_backdropnumbername"/>
@@ -311,13 +310,17 @@ const sound = function () {
`;
};
const events = function () {
const events = function (isStage) {
return `
<category name="Events" colour="#FFD500" secondaryColour="#CC9900">
<block type="event_whenflagclicked"/>
<block type="event_whenkeypressed">
</block>
<block type="event_whenthisspriteclicked"/>
${isStage ? `
<block type="event_whenstageclicked"/>
` : `
<block type="event_whenthisspriteclicked"/>
`}
<block type="event_whenbackdropswitchesto">
</block>
${blockSeparator}
@@ -431,7 +434,11 @@ const sensing = function (isStage) {
</block>
<block id="answer" type="sensing_answer"/>
${blockSeparator}
<block type="sensing_keypressed"/>
<block type="sensing_keypressed">
<value name="KEY_OPTION">
<shadow type="sensing_keyoptions"/>
</value>
</block>
<block type="sensing_mousedown"/>
<block type="sensing_mousex"/>
<block type="sensing_mousey"/>
+1 -8
View File
@@ -52,11 +52,6 @@ const vmListenerHOC = function (WrappedComponent) {
keyCode: e.keyCode,
isDown: true
});
// Don't stop browser keyboard shortcuts
if (e.metaKey || e.altKey || e.ctrlKey) return;
e.preventDefault();
}
handleKeyUp (e) {
// Always capture up events,
@@ -99,9 +94,7 @@ const vmListenerHOC = function (WrappedComponent) {
attachKeyboardEvents: true
};
const mapStateToProps = state => ({
vm: state.vm,
hoveredSprite: state.hoveredTarget.sprite,
editingTarget: state.targets.editingTarget
vm: state.vm
});
const mapDispatchToProps = dispatch => ({
onTargetsUpdate: data => {
+11
View File
@@ -8,6 +8,7 @@ const MODAL_COSTUME_LIBRARY = 'costumeLibrary';
const MODAL_EXTENSION_LIBRARY = 'extensionLibrary';
const MODAL_FEEDBACK_FORM = 'feedbackForm';
const MODAL_IMPORT_INFO = 'importInfo';
const MODAL_LOADING_PROJECT = 'loadingProject';
const MODAL_PREVIEW_INFO = 'previewInfo';
const MODAL_SOUND_LIBRARY = 'soundLibrary';
const MODAL_SPRITE_LIBRARY = 'spriteLibrary';
@@ -20,6 +21,7 @@ const initialState = {
[MODAL_EXTENSION_LIBRARY]: false,
[MODAL_FEEDBACK_FORM]: false,
[MODAL_IMPORT_INFO]: false,
[MODAL_LOADING_PROJECT]: false,
[MODAL_PREVIEW_INFO]: true,
[MODAL_SOUND_LIBRARY]: false,
[MODAL_SPRITE_LIBRARY]: false,
@@ -73,6 +75,10 @@ const openImportInfo = function () {
analytics.pageview('modals/import');
return openModal(MODAL_IMPORT_INFO);
};
const openLoadingProject = function () {
analytics.pageview('modals/loading');
return openModal(MODAL_LOADING_PROJECT);
};
const openPreviewInfo = function () {
analytics.pageview('/modals/preview');
return openModal(MODAL_PREVIEW_INFO);
@@ -104,6 +110,9 @@ const closeFeedbackForm = function () {
const closeImportInfo = function () {
return closeModal(MODAL_IMPORT_INFO);
};
const closeLoadingProject = function () {
return closeModal(MODAL_LOADING_PROJECT);
};
const closePreviewInfo = function () {
return closeModal(MODAL_PREVIEW_INFO);
};
@@ -123,6 +132,7 @@ export {
openExtensionLibrary,
openFeedbackForm,
openImportInfo,
openLoadingProject,
openPreviewInfo,
openSoundLibrary,
openSpriteLibrary,
@@ -132,6 +142,7 @@ export {
closeExtensionLibrary,
closeFeedbackForm,
closeImportInfo,
closeLoadingProject,
closePreviewInfo,
closeSpriteLibrary,
closeSoundLibrary,
+3
View File
@@ -34,8 +34,11 @@ class SeleniumHelper {
}
getDriver () {
const chromeCapabilities = webdriver.Capabilities.chrome();
chromeCapabilities.set('chromeOptions', {args: ['--headless']});
this.driver = new webdriver.Builder()
.forBrowser('chrome')
.withCapabilities(chromeCapabilities)
.build();
return this.driver;
}
@@ -5,5 +5,9 @@ exports[`ButtonComponent matches snapshot 1`] = `
className=""
onClick={[Function]}
role="button"
/>
>
<div
className={undefined}
/>
</span>
`;
@@ -1,5 +1,84 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SpriteSelectorItemComponent matches snapshot when given a number to show 1`] = `
<div
className="react-contextmenu-wrapper ponies undefined"
onClick={[Function]}
onContextMenu={[Function]}
onMouseDown={[Function]}
onMouseEnter={undefined}
onMouseLeave={undefined}
onMouseOut={[Function]}
onMouseUp={[Function]}
onTouchEnd={[Function]}
onTouchStart={[Function]}
>
<div
aria-label="Close"
className=""
onClick={[Function]}
role="button"
tabIndex="0"
>
<img
className={undefined}
src="test-file-stub"
/>
</div>
<div
className={undefined}
>
5
</div>
<canvas
className={undefined}
height={32}
style={
Object {
"height": "32px",
"width": "32px",
}
}
width={32}
/>
<div
className={undefined}
>
Pony sprite
</div>
<nav
className="react-contextmenu"
onContextMenu={[Function]}
onMouseLeave={[Function]}
role="menu"
style={
Object {
"opacity": 0,
"pointerEvents": "none",
"position": "fixed",
}
}
tabIndex="-1"
>
<div
aria-disabled="false"
aria-orientation={null}
className="react-contextmenu-item"
onClick={[Function]}
onMouseLeave={[Function]}
onMouseMove={[Function]}
onTouchEnd={[Function]}
role="menuitem"
tabIndex="-1"
>
<span>
delete
</span>
</div>
</nav>
</div>
`;
exports[`SpriteSelectorItemComponent matches snapshot when selected 1`] = `
<div
className="react-contextmenu-wrapper ponies undefined"
@@ -11,6 +11,7 @@ describe('SpriteSelectorItemComponent', () => {
let onClick;
let onDeleteButtonClick;
let selected;
let number;
// Wrap this in a function so it gets test specific states and can be reused.
const getComponent = function () {
@@ -19,6 +20,7 @@ describe('SpriteSelectorItemComponent', () => {
className={className}
costumeURL={costumeURL}
name={name}
number={number}
selected={selected}
onClick={onClick}
onDeleteButtonClick={onDeleteButtonClick}
@@ -33,6 +35,8 @@ describe('SpriteSelectorItemComponent', () => {
onClick = jest.fn();
onDeleteButtonClick = jest.fn();
selected = true;
// Reset number to undefined since it is an optional prop
number = undefined; // eslint-disable-line no-undefined
});
test('matches snapshot when selected', () => {
@@ -40,6 +44,12 @@ describe('SpriteSelectorItemComponent', () => {
expect(component.toJSON()).toMatchSnapshot();
});
test('matches snapshot when given a number to show', () => {
number = 5;
const component = componentWithIntl(getComponent());
expect(component.toJSON()).toMatchSnapshot();
});
test('does not have a close box when not selected', () => {
selected = false;
const wrapper = shallowWithIntl(getComponent());