Merge remote-tracking branch 'upstream/develop' into scratch-desktop
This commit is contained in:
commit
94901b33fe
17 files changed
+136
-84
No files matched your search
@@ -4,6 +4,7 @@
|
||||
# NPM
|
||||
/node_modules
|
||||
npm-*
|
||||
/package-lock.json
|
||||
|
||||
# Testing
|
||||
/.nyc_output
|
||||
|
||||
+4
-4
@@ -56,7 +56,7 @@
|
||||
"eslint": "^5.0.1",
|
||||
"eslint-config-scratch": "^5.0.0",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-react": "^7.5.1",
|
||||
"eslint-plugin-react": "7.11.1",
|
||||
"file-loader": "2.0.0",
|
||||
"get-float-time-domain-data": "0.1.0",
|
||||
"get-user-media-promise": "1.1.4",
|
||||
@@ -103,14 +103,14 @@
|
||||
"redux-mock-store": "^1.2.3",
|
||||
"redux-throttle": "0.1.1",
|
||||
"rimraf": "^2.6.1",
|
||||
"scratch-audio": "0.1.0-prerelease.20181023202904",
|
||||
"scratch-audio": "0.1.0-prerelease.20190108181031",
|
||||
"scratch-blocks": "0.1.0-prerelease.1545364693",
|
||||
"scratch-l10n": "3.1.20181220222259",
|
||||
"scratch-paint": "0.2.0-prerelease.20181220194927",
|
||||
"scratch-render": "0.1.0-prerelease.20181226153401",
|
||||
"scratch-render": "0.1.0-prerelease.20190108175224",
|
||||
"scratch-storage": "1.2.2",
|
||||
"scratch-svg-renderer": "0.2.0-prerelease.20181220183040",
|
||||
"scratch-vm": "0.2.0-prerelease.20181226213940",
|
||||
"scratch-vm": "0.2.0-prerelease.20190107184530",
|
||||
"selenium-webdriver": "3.6.0",
|
||||
"startaudiocontext": "1.2.1",
|
||||
"style-loader": "^0.23.0",
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.75;
|
||||
background-color: #8cbcff;
|
||||
background-color: $drop-highlight;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.75;
|
||||
background-color: #8cbcff;
|
||||
background-color: $drop-highlight;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,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, Vivaldi, Opera or Silk. We recommend trying a newer browser such as Google Chrome, Mozilla Firefox, or Microsoft Edge."
|
||||
defaultMessage="We are very sorry, but Scratch does not support this browser version. We recommend updating to the latest version of a supported browser such as Google Chrome, Mozilla Firefox, Microsoft Edge, or Apple Safari."
|
||||
description="Unsupported browser description"
|
||||
id="gui.unsupportedBrowser.description"
|
||||
/>
|
||||
|
||||
@@ -79,6 +79,7 @@ $border-radius: 0.25rem;
|
||||
font-size: 0.85rem;
|
||||
transition: 0.2s;
|
||||
user-select: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.button > img {
|
||||
|
||||
@@ -34,62 +34,68 @@ const SpriteList = function (props) {
|
||||
|
||||
return (
|
||||
<Box
|
||||
className={styles.itemsWrapper}
|
||||
className={classNames(styles.scrollWrapper, {
|
||||
[styles.scrollWrapperDragging]: draggingType === DragConstants.BACKPACK_SPRITE
|
||||
})}
|
||||
componentRef={containerRef}
|
||||
>
|
||||
{items.map((sprite, index) => {
|
||||
<Box
|
||||
className={styles.itemsWrapper}
|
||||
>
|
||||
{items.map((sprite, index) => {
|
||||
|
||||
// If the sprite has just received a block drop, used for green highlight
|
||||
const receivedBlocks = (
|
||||
hoveredTarget.sprite === sprite.id &&
|
||||
// If the sprite has just received a block drop, used for green highlight
|
||||
const receivedBlocks = (
|
||||
hoveredTarget.sprite === sprite.id &&
|
||||
sprite.id !== editingTarget &&
|
||||
hoveredTarget.receivedBlocks
|
||||
);
|
||||
);
|
||||
|
||||
// If the sprite is indicating it can receive block dropping, used for blue highlight
|
||||
let isRaised = !receivedBlocks && raised && sprite.id !== editingTarget;
|
||||
// If the sprite is indicating it can receive block dropping, used for blue highlight
|
||||
let isRaised = !receivedBlocks && raised && sprite.id !== editingTarget;
|
||||
|
||||
// A sprite is also raised if a costume or sound is being dragged.
|
||||
// Note the absence of the self-sharing check: a sprite can share assets with itself.
|
||||
// This is a quirk of 2.0, but seems worth leaving possible, it
|
||||
// allows quick (albeit unusual) duplication of assets.
|
||||
isRaised = isRaised || [
|
||||
DragConstants.COSTUME,
|
||||
DragConstants.SOUND,
|
||||
DragConstants.BACKPACK_COSTUME,
|
||||
DragConstants.BACKPACK_SOUND,
|
||||
DragConstants.BACKPACK_CODE].includes(draggingType);
|
||||
// A sprite is also raised if a costume or sound is being dragged.
|
||||
// Note the absence of the self-sharing check: a sprite can share assets with itself.
|
||||
// This is a quirk of 2.0, but seems worth leaving possible, it
|
||||
// allows quick (albeit unusual) duplication of assets.
|
||||
isRaised = isRaised || [
|
||||
DragConstants.COSTUME,
|
||||
DragConstants.SOUND,
|
||||
DragConstants.BACKPACK_COSTUME,
|
||||
DragConstants.BACKPACK_SOUND,
|
||||
DragConstants.BACKPACK_CODE].includes(draggingType);
|
||||
|
||||
return (
|
||||
<SortableAsset
|
||||
className={classNames(styles.spriteWrapper, {
|
||||
[styles.placeholder]: isSpriteDrag && index === draggingIndex})}
|
||||
index={isSpriteDrag ? ordering.indexOf(index) : index}
|
||||
key={sprite.name}
|
||||
onAddSortable={onAddSortable}
|
||||
onRemoveSortable={onRemoveSortable}
|
||||
>
|
||||
<SpriteSelectorItem
|
||||
asset={sprite.costume && sprite.costume.asset}
|
||||
className={classNames(styles.sprite, {
|
||||
[styles.raised]: isRaised,
|
||||
[styles.receivedBlocks]: receivedBlocks
|
||||
})}
|
||||
dragPayload={sprite}
|
||||
dragType={DragConstants.SPRITE}
|
||||
id={sprite.id}
|
||||
index={index}
|
||||
key={sprite.id}
|
||||
name={sprite.name}
|
||||
selected={sprite.id === selectedId}
|
||||
onClick={onSelectSprite}
|
||||
onDeleteButtonClick={onDeleteSprite}
|
||||
onDuplicateButtonClick={onDuplicateSprite}
|
||||
onExportButtonClick={onExportSprite}
|
||||
/>
|
||||
</SortableAsset>
|
||||
);
|
||||
})}
|
||||
return (
|
||||
<SortableAsset
|
||||
className={classNames(styles.spriteWrapper, {
|
||||
[styles.placeholder]: isSpriteDrag && index === draggingIndex})}
|
||||
index={isSpriteDrag ? ordering.indexOf(index) : index}
|
||||
key={sprite.name}
|
||||
onAddSortable={onAddSortable}
|
||||
onRemoveSortable={onRemoveSortable}
|
||||
>
|
||||
<SpriteSelectorItem
|
||||
asset={sprite.costume && sprite.costume.asset}
|
||||
className={classNames(styles.sprite, {
|
||||
[styles.raised]: isRaised,
|
||||
[styles.receivedBlocks]: receivedBlocks
|
||||
})}
|
||||
dragPayload={sprite}
|
||||
dragType={DragConstants.SPRITE}
|
||||
id={sprite.id}
|
||||
index={index}
|
||||
key={sprite.id}
|
||||
name={sprite.name}
|
||||
selected={sprite.id === selectedId}
|
||||
onClick={onSelectSprite}
|
||||
onDeleteButtonClick={onDeleteSprite}
|
||||
onDuplicateButtonClick={onDuplicateSprite}
|
||||
onExportButtonClick={onExportSprite}
|
||||
/>
|
||||
</SortableAsset>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -55,6 +55,10 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.scroll-wrapper-dragging {
|
||||
background-color: $drop-highlight;
|
||||
}
|
||||
|
||||
.items-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -80,12 +84,12 @@
|
||||
}
|
||||
|
||||
.raised {
|
||||
background-color: #8cbcff;
|
||||
background-color: $drop-highlight;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.raised:hover {
|
||||
background-color: #8cbcff;
|
||||
background-color: $drop-highlight;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
@@ -94,7 +98,7 @@
|
||||
animation-duration: 500ms;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: ease-in-out;
|
||||
background-color: #8cbcff;
|
||||
background-color: $drop-highlight;
|
||||
}
|
||||
|
||||
@keyframes wiggle {
|
||||
|
||||
@@ -100,20 +100,18 @@ const SpriteSelectorComponent = function (props) {
|
||||
onChangeY={onChangeSpriteY}
|
||||
/>
|
||||
|
||||
<Box className={styles.scrollWrapper}>
|
||||
<SpriteList
|
||||
editingTarget={editingTarget}
|
||||
hoveredTarget={hoveredTarget}
|
||||
items={Object.keys(sprites).map(id => sprites[id])}
|
||||
raised={raised}
|
||||
selectedId={selectedId}
|
||||
onDeleteSprite={onDeleteSprite}
|
||||
onDrop={onDrop}
|
||||
onDuplicateSprite={onDuplicateSprite}
|
||||
onExportSprite={onExportSprite}
|
||||
onSelectSprite={onSelectSprite}
|
||||
/>
|
||||
</Box>
|
||||
<SpriteList
|
||||
editingTarget={editingTarget}
|
||||
hoveredTarget={hoveredTarget}
|
||||
items={Object.keys(sprites).map(id => sprites[id])}
|
||||
raised={raised}
|
||||
selectedId={selectedId}
|
||||
onDeleteSprite={onDeleteSprite}
|
||||
onDrop={onDrop}
|
||||
onDuplicateSprite={onDuplicateSprite}
|
||||
onExportSprite={onExportSprite}
|
||||
onSelectSprite={onSelectSprite}
|
||||
/>
|
||||
<ActionMenu
|
||||
className={styles.addButton}
|
||||
img={spriteIcon}
|
||||
|
||||
@@ -100,7 +100,7 @@ $header-height: calc($stage-menu-height - 2px);
|
||||
}
|
||||
|
||||
.raised, .raised .header {
|
||||
background-color: #8cbcff;
|
||||
background-color: $drop-highlight;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
*/
|
||||
display: block;
|
||||
|
||||
/* Attach border radius directly to canvas to prevent needing overflow:hidden; */
|
||||
border-radius: $space;
|
||||
border: $stage-standard-border-width solid $ui-black-transparent;
|
||||
overflow: hidden;
|
||||
|
||||
/* @todo: This is for overriding the value being set somewhere. Where is it being set? */
|
||||
background-color: transparent;
|
||||
|
||||
@@ -48,18 +48,25 @@ const StageComponent = props => {
|
||||
}}
|
||||
onDoubleClick={onDoubleClick}
|
||||
>
|
||||
<DOMElementRenderer
|
||||
<Box
|
||||
className={classNames(
|
||||
styles.stage,
|
||||
{[styles.stageOverlayContent]: isFullScreen}
|
||||
)}
|
||||
domElement={canvas}
|
||||
style={{
|
||||
height: stageDimensions.height,
|
||||
width: stageDimensions.width
|
||||
}}
|
||||
{...boxProps}
|
||||
/>
|
||||
>
|
||||
<DOMElementRenderer
|
||||
domElement={canvas}
|
||||
style={{
|
||||
height: stageDimensions.height,
|
||||
width: stageDimensions.width
|
||||
}}
|
||||
{...boxProps}
|
||||
/>
|
||||
</Box>
|
||||
<Box className={styles.monitorWrapper}>
|
||||
<MonitorList
|
||||
draggable={useEditorDragStyle}
|
||||
|
||||
@@ -40,3 +40,5 @@ $extensions-primary: hsla(163, 85%, 40%, 1); /* #0FBD8C */
|
||||
$extensions-tertiary: hsla(163, 85%, 30%, 1); /* #0B8E69 */
|
||||
$extensions-transparent: hsla(163, 85%, 40%, 0.35); /* 35% transparent version of extensions-primary */
|
||||
$extensions-light: hsla(163, 57%, 85%, 1); /* opaque version of extensions-transparent, on white bg */
|
||||
|
||||
$drop-highlight: hsla(215, 100%, 77%); /* lighter than motion-primary */
|
||||
@@ -4,6 +4,17 @@ import omit from 'lodash.omit';
|
||||
import {connect} from 'react-redux';
|
||||
import {setFontsLoaded} from '../reducers/fonts-loaded';
|
||||
|
||||
// This list is from scratch-render-fonts:
|
||||
// https://github.com/LLK/scratch-render-fonts/blob/master/src/index.js#L4
|
||||
const FONTS = [
|
||||
'Sans Serif',
|
||||
'Serif',
|
||||
'Handwriting',
|
||||
'Marker',
|
||||
'Curly',
|
||||
'Pixel',
|
||||
'Scratch'
|
||||
];
|
||||
/* Higher Order Component to provide behavior for loading fonts.
|
||||
* @param {React.Component} WrappedComponent component to receive fontsLoaded prop
|
||||
* @returns {React.Component} component with font loading behavior
|
||||
@@ -22,8 +33,12 @@ const FontLoaderHOC = function (WrappedComponent) {
|
||||
typeof document.fonts.values === 'function' &&
|
||||
typeof document.fonts.values()[Symbol.iterator] === 'function') {
|
||||
for (const fontFace of document.fonts.values()) {
|
||||
fontPromises.push(fontFace.loaded);
|
||||
fontFace.load();
|
||||
// Only load fonts from this list. If we load all fonts on the document, we may block on
|
||||
// loading fonts from things like chrome extensions.
|
||||
if (FONTS.indexOf(fontFace.family) !== -1) {
|
||||
fontPromises.push(fontFace.loaded);
|
||||
fontFace.load();
|
||||
}
|
||||
}
|
||||
}
|
||||
return fontPromises;
|
||||
|
||||
@@ -210,6 +210,13 @@ const ProjectSaverHOC = function (WrappedComponent) {
|
||||
storeProject (projectId, requestParams) {
|
||||
requestParams = requestParams || {};
|
||||
this.clearAutoSaveTimeout();
|
||||
// Serialize VM state now before embarking on
|
||||
// the asynchronous journey of storing assets to
|
||||
// the server. This ensures that assets don't update
|
||||
// while in the process of saving a project (e.g. the
|
||||
// serialized project refers to a newer asset than what
|
||||
// we just finished saving).
|
||||
const savedVMState = this.props.vm.toJSON();
|
||||
return Promise.all(this.props.vm.assets
|
||||
.filter(asset => !asset.clean)
|
||||
.map(
|
||||
@@ -224,7 +231,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
|
||||
)
|
||||
).then(() => {
|
||||
const opts = {
|
||||
body: this.props.vm.toJSON(),
|
||||
body: savedVMState,
|
||||
// If we set json:true then the body is double-stringified, so don't
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
||||
@@ -69,6 +69,10 @@ const getStageDimensions = (stageSize, isFullScreen) => {
|
||||
stageDimensions.width = stageDimensions.scale * stageDimensions.widthDefault;
|
||||
}
|
||||
|
||||
// Round off dimensions to prevent resampling/blurriness
|
||||
stageDimensions.height = Math.round(stageDimensions.height);
|
||||
stageDimensions.width = Math.round(stageDimensions.width);
|
||||
|
||||
return stageDimensions;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,11 +6,18 @@ import bowser from 'bowser';
|
||||
*/
|
||||
export default function () {
|
||||
if (bowser.msie ||
|
||||
bowser.vivaldi ||
|
||||
bowser.opera ||
|
||||
bowser.silk) {
|
||||
return false;
|
||||
}
|
||||
// @todo Should also test for versions of supported browsers
|
||||
return true;
|
||||
// IMPORTANT: If you change versions here, also change them in www
|
||||
// minimum versions for recommended browsers
|
||||
const minVersions = {
|
||||
chrome: '63',
|
||||
msedge: '15',
|
||||
firefox: '57',
|
||||
safari: '11'
|
||||
};
|
||||
// strict mode == false so any browser not mentioned in the min Versions is ok
|
||||
return bowser.check(minVersions, false);
|
||||
}
|
||||
Reference in new issue
Block a user