Partially Implement GH-830: Add coming soon tooltips (#1069)

* Implement GH-830: Add coming soon tooltips

This implements coming soon tooltips for:
* the small stage size
* save, load and language

It also creates the component that can be copied over into the paint editor for use there as well.

Lastly, this does a small refactor on the full screen implementation to include multiple small screen sizes too.
This commit is contained in:
Matthew Taylor authored and GitHub committed 2017-12-20 14:49:27 -05:00
1 parent 6e743057f8
commit 8dc26d8d30
33 files changed
+711 -439

No files matched your search

+1
View File
@@ -79,6 +79,7 @@
"react-style-proptype": "3.1.0",
"react-tabs": "2.1.1",
"react-test-renderer": "16.2.0",
"react-tooltip": "3.4.0",
"redux": "3.7.0",
"redux-mock-store": "^1.2.3",
"redux-throttle": "0.1.1",
+21 -13
View File
@@ -9,23 +9,31 @@ const ButtonComponent = ({
onClick,
children,
...props
}) => (
<span
className={classNames(
styles.button,
className
)}
role="button"
onClick={onClick}
{...props}
>
{children}
</span>
);
}) => {
if (props.disabled === true) {
onClick = function () {};
}
return (
<span
className={classNames(
styles.button,
className
)}
role="button"
onClick={onClick}
{...props}
>
{children}
</span>
);
};
ButtonComponent.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
disabled: PropTypes.bool,
onClick: PropTypes.func.isRequired
};
export default ButtonComponent;
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

@@ -0,0 +1,68 @@
/*
* NOTE: the copious use of `important` is needed to overwrite
* the default tooltip styling, and is required by the 3rd party
* library being used, `react-tooltip`
*/
@import "../../css/colors.css";
.coming-soon {
background-color: $data-primary !important;
border: 1px solid hsla(0, 0%, 0%, .1) !important;
border-radius: .25rem !important;
box-shadow: 0 0 .5rem hsla(0, 0%, 0%, .25) !important;
padding: .75rem 1rem !important;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important;
font-size: 1rem !important;
line-height: 1.25rem !important;
z-index: 100 !important;
}
.coming-soon:after {
content: "";
border-top: 1px solid hsla(0, 0%, 0%, .1) !important;
border-left: 0 !important;
border-bottom: 0 !important;
border-right: 1px solid hsla(0, 0%, 0%, .1) !important;
border-radius: .25rem;
background-color: $data-primary !important;
height: 1rem !important;
width: 1rem !important;
}
.show,
.show:before,
.show:after {
opacity: 1 !important;
}
.left:after {
margin-top: -.5rem !important;
right: -.5rem !important;
transform: rotate(45deg) !important;
}
.right:after {
margin-top: -.5rem !important;
left: -.5rem !important;
transform: rotate(-135deg) !important;
}
.top:after {
margin-right: -.5rem !important;
bottom: -.5rem !important;
transform: rotate(135deg) !important;
}
.bottom:after {
margin-left: -.5rem !important;
top: -.5rem !important;
transform: rotate(-45deg) !important;
}
.coming-soon-image {
margin-left: .125rem;
width: 1.25rem;
height: 1.25rem;
vertical-align: middle;
}
+143
View File
@@ -0,0 +1,143 @@
import bindAll from 'lodash.bindall';
import classNames from 'classnames';
import {defineMessages, injectIntl, intlShape, FormattedMessage} from 'react-intl';
import PropTypes from 'prop-types';
import React from 'react';
import ReactTooltip from 'react-tooltip';
import styles from './coming-soon.css';
import awwCatIcon from './aww-cat.png';
import coolCatIcon from './cool-cat.png';
const messages = defineMessages({
message1: {
defaultMessage: 'Don\'t worry, we\'re on it {emoji}',
description: 'One of the "coming soon" random messages for yet-to-be-done features',
id: 'gui.comingSoon.message1'
},
message2: {
defaultMessage: 'Coming Soon...',
description: 'One of the "coming soon" random messages for yet-to-be-done features',
id: 'gui.comingSoon.message2'
},
message3: {
defaultMessage: 'We\'re working on it {emoji}',
description: 'One of the "coming soon" random messages for yet-to-be-done features',
id: 'gui.comingSoon.message3'
}
});
class ComingSoonContent extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'setHide',
'setShow',
'getRandomMessage'
]);
this.state = {
isShowing: false
};
}
setShow () {
// needed to set the opacity to 1, since the default is .9 on show
this.setState({isShowing: true});
}
setHide () {
this.setState({isShowing: false});
}
getRandomMessage () {
// randomly chooses a messages from `messages` to display in the tooltip.
const images = [awwCatIcon, coolCatIcon];
const messageNumber = Math.floor(Math.random() * Object.keys(messages).length) + 1;
const imageNumber = Math.floor(Math.random() * Object.keys(images).length);
return (
<FormattedMessage
{...messages[`message${messageNumber}`]}
values={{
emoji: (
<img
className={styles.comingSoonImage}
src={images[imageNumber]}
/>
)
}}
/>
);
}
render () {
return (
<ReactTooltip
afterHide={this.setHide}
afterShow={this.setShow}
className={classNames(
styles.comingSoon,
this.props.className,
{
[styles.show]: (this.state.isShowing),
[styles.left]: (this.props.place === 'left'),
[styles.right]: (this.props.place === 'right'),
[styles.top]: (this.props.place === 'top'),
[styles.bottom]: (this.props.place === 'bottom')
}
)}
getContent={this.getRandomMessage}
id={this.props.tooltipId}
/>
);
}
}
ComingSoonContent.propTypes = {
className: PropTypes.string,
intl: intlShape,
place: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
tooltipId: PropTypes.string.isRequired
};
ComingSoonContent.defaultProps = {
place: 'bottom'
};
const ComingSoon = injectIntl(ComingSoonContent);
const ComingSoonTooltip = props => (
<div className={props.className}>
<div
data-delay-hide={props.delayHide}
data-delay-show={props.delayShow}
data-effect="solid"
data-for={props.tooltipId}
data-place={props.place}
data-tip="tooltip"
>
{props.children}
</div>
<ComingSoon
className={props.tooltipClassName}
place={props.place}
tooltipId={props.tooltipId}
/>
</div>
);
ComingSoonTooltip.propTypes = {
children: PropTypes.node.isRequired,
className: PropTypes.string,
delayHide: PropTypes.number,
delayShow: PropTypes.number,
place: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
tooltipClassName: PropTypes.string,
tooltipId: PropTypes.string.isRequired
};
ComingSoonTooltip.defaultProps = {
delayHide: 0,
delayShow: 0
};
export {
ComingSoon as ComingSoonComponent,
ComingSoonTooltip
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

-8
View File
@@ -143,14 +143,6 @@
overflow: hidden;
}
.stage-menu-wrapper {
display: flex;
flex-shrink: 0;
align-items: center;
height: $stage-menu-height;
padding: $space;
}
.extension-button-container {
width: 3.25rem;
height: 3.25rem;
+1 -7
View File
@@ -112,13 +112,7 @@ const GUIComponent = props => {
<Box className={styles.stageAndTargetWrapper}>
<Box className={styles.stageMenuWrapper}>
<MediaQuery minWidth={layout.fullSizeMinWidth}>{isFullSize => (
<StageHeader
height={isFullSize ? layout.fullStageHeight : layout.smallerStageHeight}
vm={vm}
width={isFullSize ? layout.fullStageWidth : layout.smallerStageWidth}
/>
)}</MediaQuery>
<StageHeader vm={vm} />
</Box>
<Box className={styles.stageWrapper}>
<MediaQuery minWidth={layout.fullSizeMinWidth}>{isFullSize => (
@@ -1,72 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve">
<g>
<polygon fill="#999999" points="148.7,59.1 68,30.6 68,206.1 148.7,180 "/>
<polygon fill="#FFFFFF" points="146.7,59 230.5,30.5 230.5,206 146.7,180 "/>
<polygon fill="#FFFFFF" points="47.1,236.9 146.7,203.7 146.7,58.9 47.1,92.2 "/>
<polygon fill="#999999" points="192.1,239.1 206.2,262.3 213.7,240.7 "/>
<g>
<path fill="#999999" d="M81,108.8c-0.5-0.5,0.7,4.2,2.4,6c3,3,5.4,3.4,6.6,3.5c2.8,0.1,6.2-0.7,8.2-1.5c2-0.8,5.4-2.6,6.7-5.2
c0.3-0.5,1-1.5,0.6-3.7c-0.4-1.7-1.5-2.4-2.8-2.3c-1.4,0.1-5.5,1.2-7.4,1.8c-2,0.6-6.1,1.8-7.9,2.2C85.5,110,81.6,109.4,81,108.8z
"/>
<path fill="#999999" d="M131.2,165.8c-0.8-0.3-17-7-19.3-8.1c-1.9-0.9-6.5-2.9-8.7-3.7c6.1-9.4,10-16.6,10.5-17.7
c1-2,7.4-14.7,7.6-15.4c0.1-0.8,0.3-3.7,0.2-4.4c-0.1-0.7-2.5,0.7-5.7,1.7c-3.2,1.1-9.4,5.1-11.7,5.6c-2.4,0.5-10,3.4-13.9,4.7
c-3.9,1.3-11.3,3.5-14.3,4.4c-3,0.8-5.7,0.9-7.4,1.4c0,0,0.2,2.4,0.7,3.1c0.4,0.7,2.1,2.5,3.9,2.9c1.9,0.5,5,0.3,6.4,0
c1.4-0.3,3.8-1.5,4.2-2c0.3-0.5-0.2-2.2,0.4-2.6c0.6-0.5,8-2.2,10.8-3.1c2.8-0.9,13.5-4.6,15-4.4c-0.5,1.5-9.1,18.6-11.9,23.7
c-2.8,5.1-18.9,27.5-22.3,31.4c-2.6,3-8.9,10.7-11.1,12.4c0.6,0.2,4.5-0.2,5.2-0.6c4.4-2.7,11.8-11.9,14.2-14.7
c7.1-8.3,13.3-17,18.2-24.5h0c1,0.4,8.7,6.7,10.8,8.1c2,1.4,10,5.9,11.8,6.6c1.7,0.7,8.4,3.8,8.7,2.8
C133.5,172.2,132,166.1,131.2,165.8z"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#999999" d="M93.7,250.4c1.6,1,3,1.7,4.7,2.5c3.3,1.6,7,3.4,10.5,4.7
c4.8,1.8,9.7,3.3,14.5,4.4c2.7,0.6,5.6,1.1,8.5,1.6c0.3,0,8,1,9.5,1h7.8c3-0.3,5.9-0.4,8.9-0.9c2.4-0.3,5.1-0.8,7.7-1.4
c1.9-0.4,3.9-0.9,5.8-1.5c1.8-0.5,3.9-1.2,5.9-1.9c1.3-0.4,2.7-1,4.1-1.6c1.1-0.5,2.5-1.1,3.8-1.6c1.6-0.7,3.4-1.6,5.1-2.5
c1.4-0.7,2.9-1.6,4.4-2.4c1.1-0.6,3.7-2.6,5.1-2.6c1.6,0,2.6,1.4,2.6,2.6c0,2.5-3.4,3.3-4.9,4.4c-1.6,1.1-3.6,2-5.4,2.9
c-3.5,1.8-7,3.4-10.4,4.7c-4.4,1.6-9.3,3.2-13.6,4.2c-1.6,0.3-3.3,0.8-4.9,1c-0.9,0.2-9.9,1.6-12.4,1.6h-11.4c-3-0.3-6.2-0.6-9.3-1
c-2.7-0.4-5.5-1-8.2-1.6c-2.1-0.4-4.3-1-6.3-1.6c-3.5-1-6.8-2.2-10.1-3.5c-6-2.2-12.2-5.2-18.1-9.1c-1-0.7-1.1-1.4-1.1-2.2
c0-1.3,1-2.5,2.5-2.5C90.4,248.2,93.2,250.1,93.7,250.4z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#999999" d="M144,201.7l-94.3,31.4v-139L144,62.7V201.7z M149.3,58.6v145.3
c-0.1,0.4-0.3,0.9-0.6,1.3c-0.2,0.3-0.5,0.6-0.8,0.7c-2.2,0.9-99.5,33.6-100.8,33.6c-1,0-2-0.7-2.5-1.8c0-0.1-0.1-0.2-0.1-0.3V91.9
c0.2-0.4,0.3-1,0.6-1.4c0.7-1,1.9-1.1,2.7-1.4c1.5-0.5,97.4-32.7,98.8-32.7C147.4,56.4,149.3,57.1,149.3,58.6z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#999999" d="M227.8,202.4L149.4,178V60.9l78.4-26.6V202.4z M233.1,30.8v174.9
c-0.1,2-1.5,2.9-2.8,2.9c-1.1,0-9.3-2.8-10.6-3.2c-10.9-3.4-21.9-6.7-32.7-10.1c-2.4-0.8-4.9-1.6-7.3-2.3c-2.1-0.6-4.3-1.3-6.4-2
c-9.3-2.9-18.7-5.7-27.9-8.8c-0.3-0.1-1.2-1.3-1.2-1.6V58.4c0.2-0.4,0.3-1,0.8-1.3c0.7-0.8,30.4-10.6,42-14.5
c3.1-1.1,42.1-14.5,43.3-14.5C231.9,28,233.1,29.1,233.1,30.8z"/>
<polygon fill="#999999" points="253,239.1 148.2,205.7 148.7,60.3 253,93.5 "/>
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M200.2,125.2l-10.3,24.9l18.9,5.7L200.2,125.2z M194,101.8
l13.5,4.1l24.6,88.6l-13.9-4.2l-5-18.2l-28.7-8.7l-6.2,14.8l-13.9-4.2L194,101.8z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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 -->
<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)">
<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>
<path d="M0.955011765,5.94663529 L15.2684235,5.94663529" id="Stroke-7"></path>
<path d="M8.11218824,0.590023529 L8.11218824,15.6375529" id="Stroke-9"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1,3 +1,4 @@
@import "../../css/colors.css";
@import "../../css/units.css";
.group {
@@ -9,7 +10,7 @@
.language-icon {
height: 2rem;
display:none;
display: none;
}
.language-select {
@@ -19,7 +20,7 @@
user-select: none;
outline: none;
background: rgba(255, 255, 255, 0.5);
color: #3373cc;
color: $motion-tertiary;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
@@ -2,6 +2,7 @@ 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 styles from './language-selector.css';
@@ -12,27 +13,33 @@ const LanguageSelector = ({
...props
}) => (
<Box {...props}>
<div className={styles.group}>
<img
className={styles.languageIcon}
src={languageIcon}
/>
<select
aria-label="language selector"
className={styles.languageSelect}
value={currentLocale}
onChange={onChange}
>
{Object.keys(locales).map(locale => (
<option
key={locale}
value={locale}
>
{locales[locale].name}
</option>
))}
</select>
</div>
<ComingSoonTooltip
place="bottom"
tooltipId="language-selector"
>
<div className={styles.group}>
<img
className={styles.languageIcon}
src={languageIcon}
/>
<select
disabled
aria-label="language selector"
className={styles.languageSelect}
value={currentLocale}
onChange={onChange}
>
{Object.keys(locales).map(locale => (
<option
key={locale}
value={locale}
>
{locales[locale].name}
</option>
))}
</select>
</div>
</ComingSoonTooltip>
</Box>
);
+19 -7
View File
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import ButtonComponent from '../button/button.jsx';
import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx';
import styles from './load-button.css';
@@ -13,13 +14,24 @@ const LoadButtonComponent = ({
...props
}) => (
<span {...props}>
<ButtonComponent onClick={onClick}>{title}</ButtonComponent>
<input
className={styles.fileInput}
ref={inputRef}
type="file"
onChange={onChange}
/>
<ComingSoonTooltip
place="bottom"
tooltipId="load-button"
>
<ButtonComponent
disabled
onClick={onClick}
>
{title}
</ButtonComponent>
<input
disabled
className={styles.fileInput}
ref={inputRef}
type="file"
onChange={onChange}
/>
</ComingSoonTooltip>
</span>
);
+3 -7
View File
@@ -1,3 +1,4 @@
@import "../../css/colors.css";
@import "../../css/units.css";
.menu-bar {
@@ -23,7 +24,7 @@
width: 100%;
*/
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
background-color: #4c97ff;
background-color: $motion-primary;
color: white;
}
@@ -56,11 +57,6 @@
line-height: $menu-bar-height;
cursor: pointer;
text-decoration: none;
color: white;
color: $motion-tertiary;
user-select: none;
}
.menu-item:hover {
opacity: 0.8;
background: rgba(255, 255, 255, 0.2)
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>dropdown-caret-gray</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-gray" fill="#575E75">
<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" id="dropdown-caret"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 950 B

+26
View File
@@ -49,3 +49,29 @@
.button-row button + button {
margin-left: 0.5rem;
}
.more-options {
border-top: 1px dashed hsla(0, 0%, 0%, .25);
overflow: visible;
padding: 1rem;
text-align: center;
margin: 0 0 1rem;
}
.more-options-accordion {
width: 60%;
margin: 0 auto;
}
.more-options-text {
opacity: .5;
}
.more-options-icon {
width: .75rem;
height: .75rem;
margin-left: .5rem;
vertical-align: middle;
padding-bottom: .2rem;
opacity: .5;
}
+31 -1
View File
@@ -1,10 +1,23 @@
import {defineMessages, FormattedMessage} from 'react-intl';
import PropTypes from 'prop-types';
import React from 'react';
import Modal from '../modal/modal.jsx';
import Box from '../box/box.jsx';
import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx';
import Modal from '../modal/modal.jsx';
import styles from './prompt.css';
import dropdownIcon from './icon--dropdown-caret.svg';
const messages = defineMessages({
moreOptionsMessage: {
defaultMessage: 'More Options',
description: 'Dropdown message for variable/list options',
id: 'gui.gui.variablePrompt'
}
});
const PromptComponent = props => (
<Modal
className={styles.modalContent}
@@ -24,6 +37,23 @@ const PromptComponent = props => (
onKeyPress={props.onKeyPress}
/>
</Box>
<Box className={styles.moreOptions}>
<ComingSoonTooltip
className={styles.moreOptionsAccordion}
place="right"
tooltipId="variable-options-accordion"
>
<div className={styles.moreOptionsText}>
<FormattedMessage
{...messages.moreOptionsMessage}
/>
<img
className={styles.moreOptionsIcon}
src={dropdownIcon}
/>
</div>
</ComingSoonTooltip>
</Box>
<Box className={styles.buttonRow}>
<button
className={styles.cancelButton}
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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 -->
<title>Fullscreen</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Fullscreen" fill="#575E75">
<g id="fullscreen" transform="translate(3.000000, 3.000000)">
<path d="M13.338093,4.35035264 L12.4488644,3.45883199 L9.31483512,5.83342741 C8.95713791,6.10825708 8.4389784,6.03619808 8.1648553,5.66752413 C7.94254816,5.37090918 7.94756261,4.96201625 8.1648553,4.6821592 L10.5333457,1.54005165 L9.66584641,0.668640487 C9.41679554,0.418947674 9.59397267,0.00502737208 9.93495506,0.00502737208 L13.6122161,0 C13.8244944,0.00502737208 14,0.180985395 14,0.388783441 L14,4.08055034 C14,4.42241164 13.5821294,4.59501808 13.338093,4.35035264" id="Fill-1"></path>
<path d="M0.661906989,9.64928834 L1.55113557,10.5408826 L4.68516488,8.16609118 C5.04286209,7.89123882 5.5610216,7.9649797 5.8351447,8.33200815 C6.05745184,8.62864758 6.05243739,9.03757425 5.8351447,9.3174544 L3.4649828,12.4598213 L4.33415359,13.3313043 C4.58320446,13.5810178 4.40602733,13.9949722 4.06504494,13.9949722 L0.387783893,14 C0.175505641,13.9949722 0,13.8189997 0,13.6111845 L0,9.9191129 C0,9.57722339 0.417870574,9.4046027 0.661906989,9.64928834" id="Fill-3"></path>
<path d="M0.661906989,4.35035264 L1.55113557,3.45883199 L4.68516488,5.83342741 C5.04286209,6.10825708 5.5610216,6.03619808 5.8351447,5.66752413 C6.05745184,5.37090918 6.05243739,4.96201625 5.8351447,4.6821592 L3.4649828,1.54005165 L4.33415359,0.668640487 C4.58320446,0.418947674 4.40602733,0.00502737208 4.06504494,0.00502737208 L0.387783893,0 C0.175505641,0.00502737208 0,0.180985395 0,0.388783441 L0,4.08055034 C0,4.42241164 0.417870574,4.59501808 0.661906989,4.35035264" id="Fill-5"></path>
<path d="M13.338093,9.64928834 L12.4488644,10.5408826 L9.31483512,8.16609118 C8.95713791,7.89123882 8.4389784,7.9649797 8.1648553,8.33200815 C7.94254816,8.62864758 7.94756261,9.03757425 8.1648553,9.3174544 L10.5333457,12.4598213 L9.66584641,13.3313043 C9.41679554,13.5810178 9.59397267,13.9949722 9.93495506,13.9949722 L13.6122161,14 C13.8244944,13.9949722 14,13.8189997 14,13.6111845 L14,9.9191129 C14,9.57722339 13.5821294,9.4046027 13.338093,9.64928834" id="Fill-7"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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 -->
<title>Large Stage (active)</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" stroke-linejoin="round">
<g id="Large-Stage-(active)" stroke="#4C97FF">
<g id="large-stage-(inactive)" transform="translate(3.000000, 4.000000)">
<path d="M1,0 L7,0 L7,12 L1,12 L1,12 C0.44771525,12 6.76353751e-17,11.5522847 0,11 L0,1 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z" id="Rectangle"></path>
<path d="M7,0 L13,0 L13,0 C13.5522847,-1.01453063e-16 14,0.44771525 14,1 L14,5.25 L7,5.25 L7,0 Z" id="Rectangle" fill="#4C97FF"></path>
<path d="M7,5 L14,5 L14,11 L14,11 C14,11.5522847 13.5522847,12 13,12 L7,12 L7,5 Z" id="Rectangle-Copy"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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 -->
<title>Small Stage (inactive)</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" stroke-linejoin="round">
<g id="Small-Stage-(inactive)" stroke="#575E75">
<g id="small-stage-(inactive)" transform="translate(3.000000, 4.000000)">
<path d="M1,0 L10,0 L10,12 L1,12 L1,12 C0.44771525,12 6.76353751e-17,11.5522847 0,11 L0,1 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z" id="Rectangle"></path>
<path d="M10,0 L13,0 L13,0 C13.5522847,-1.01453063e-16 14,0.44771525 14,1 L14,3 L10,3 L10,0 Z" id="Rectangle" fill="#575E75"></path>
<path d="M10,3 L14,3 L14,11 L14,11 C14,11.5522847 13.5522847,12 13,12 L10,12 L10,3 Z" id="Rectangle-Copy"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>un-fullscreen</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="un-fullscreen" fill="#575E75">
<g transform="translate(2.000000, 2.000000)">
<path d="M15.338093,4.35035264 L14.4488644,3.45883199 L11.3148351,5.83342741 C10.9571379,6.10825708 10.4389784,6.03619808 10.1648553,5.66752413 C9.94254816,5.37090918 9.94756261,4.96201625 10.1648553,4.6821592 L12.5333457,1.54005165 L11.6658464,0.668640487 C11.4167955,0.418947674 11.5939727,0.00502737208 11.9349551,0.00502737208 L15.6122161,0 C15.8244944,0.00502737208 16,0.180985395 16,0.388783441 L16,4.08055034 C16,4.42241164 15.5821294,4.59501808 15.338093,4.35035264" id="Fill-1" transform="translate(13.000000, 3.000000) rotate(180.000000) translate(-13.000000, -3.000000) "></path>
<path d="M0.661906989,11.6492883 L1.55113557,12.5408826 L4.68516488,10.1660912 C5.04286209,9.89123882 5.5610216,9.9649797 5.8351447,10.3320081 C6.05745184,10.6286476 6.05243739,11.0375743 5.8351447,11.3174544 L3.4649828,14.4598213 L4.33415359,15.3313043 C4.58320446,15.5810178 4.40602733,15.9949722 4.06504494,15.9949722 L0.387783893,16 C0.175505641,15.9949722 0,15.8189997 0,15.6111845 L0,11.9191129 C0,11.5772234 0.417870574,11.4046027 0.661906989,11.6492883" id="Fill-3" transform="translate(3.000000, 13.000000) rotate(180.000000) translate(-3.000000, -13.000000) "></path>
<path d="M0.661906989,4.35035264 L1.55113557,3.45883199 L4.68516488,5.83342741 C5.04286209,6.10825708 5.5610216,6.03619808 5.8351447,5.66752413 C6.05745184,5.37090918 6.05243739,4.96201625 5.8351447,4.6821592 L3.4649828,1.54005165 L4.33415359,0.668640487 C4.58320446,0.418947674 4.40602733,0.00502737208 4.06504494,0.00502737208 L0.387783893,0 C0.175505641,0.00502737208 0,0.180985395 0,0.388783441 L0,4.08055034 C0,4.42241164 0.417870574,4.59501808 0.661906989,4.35035264" id="Fill-5" transform="translate(3.000000, 3.000000) rotate(180.000000) translate(-3.000000, -3.000000) "></path>
<path d="M15.338093,11.6492883 L14.4488644,12.5408826 L11.3148351,10.1660912 C10.9571379,9.89123882 10.4389784,9.9649797 10.1648553,10.3320081 C9.94254816,10.6286476 9.94756261,11.0375743 10.1648553,11.3174544 L12.5333457,14.4598213 L11.6658464,15.3313043 C11.4167955,15.5810178 11.5939727,15.9949722 11.9349551,15.9949722 L15.6122161,16 C15.8244944,15.9949722 16,15.8189997 16,15.6111845 L16,11.9191129 C16,11.5772234 15.5821294,11.4046027 15.338093,11.6492883" id="Fill-7" transform="translate(13.000000, 13.000000) rotate(180.000000) translate(-13.000000, -13.000000) "></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

@@ -1,89 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
width="32"
height="32"
viewBox="0 0 32 32"
sodipodi:docname="icon--unzoom.svg"
inkscape:version="0.92+devel unknown">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="981"
id="namedview4"
showgrid="false"
inkscape:measure-start="41.6688,16.2381"
inkscape:measure-end="0,0"
inkscape:zoom="20.275"
inkscape:cx="20.257873"
inkscape:cy="15.103245"
inkscape:window-x="0"
inkscape:window-y="28"
inkscape:window-maximized="1"
inkscape:current-layer="g10" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g10"
transform="translate(0,12)">
<rect
style="fill:#4c97ff;fill-opacity:1;stroke-width:0.94703782"
id="rect4271"
width="15.349942"
height="12.743591"
x="8.2659235"
y="-2.3098626" />
<path
style="fill:#4c97ff;fill-opacity:1;stroke:none;stroke-width:1.25366771"
d="m 23.810503,-11.600711 v 7.9999999 h 8 v -2.220703 h -5.787109 v -5.7792969 z"
id="rect4356"
inkscape:connector-curvature="0" />
<path
style="fill:#4c97ff;fill-opacity:1;stroke:none;stroke-width:1.25366771"
d="M 0.27627954,-3.6685866 H 8.2762798 v -8.0000004 h -2.220703 v 5.7871094 H 0.27627954 Z"
id="rect4356-5"
inkscape:connector-curvature="0" />
<path
style="fill:#4c97ff;fill-opacity:1;stroke:none;stroke-width:1.25366771"
d="m 31.7603,11.59536 h -8 v 8 h 2.220703 V 13.808251 H 31.7603 Z"
id="rect4356-6"
inkscape:connector-curvature="0" />
<path
style="fill:#4c97ff;fill-opacity:1;stroke:none;stroke-width:1.25366771"
d="m 8.2260788,19.527481 v -8 h -8 v 2.220703 h 5.787109 v 5.779297 z"
id="rect4356-7"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

@@ -1,89 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
width="32"
height="32"
viewBox="0 0 32 32"
sodipodi:docname="icon--zoom.svg"
inkscape:version="0.92+devel unknown">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="981"
id="namedview4"
showgrid="false"
inkscape:measure-start="41.6688,16.2381"
inkscape:measure-end="0,0"
inkscape:zoom="20.275"
inkscape:cx="20.257873"
inkscape:cy="15.103245"
inkscape:window-x="0"
inkscape:window-y="28"
inkscape:window-maximized="1"
inkscape:current-layer="g10" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g10"
transform="translate(0,12)">
<rect
style="fill:#4c97ff;fill-opacity:1;stroke-width:1.43851125"
id="rect4271"
width="23.315924"
height="19.356985"
x="4.2786169"
y="-5.6201425" />
<path
style="fill:#4c97ff;fill-opacity:1;stroke:none;stroke-width:1.25366771"
d="m 31.810503,-3.600711 v -8 h -8 v 2.220703 h 5.787109 v 5.779297 z"
id="rect4356"
inkscape:connector-curvature="0" />
<path
style="fill:#4c97ff;fill-opacity:1;stroke:none;stroke-width:1.25366771"
d="M 8.2762798,-11.668587 H 0.27627954 v 8.0000004 H 2.4969826 v -5.7871095 h 5.7792972 z"
id="rect4356-5"
inkscape:connector-curvature="0" />
<path
style="fill:#4c97ff;fill-opacity:1;stroke:none;stroke-width:1.25366771"
d="m 23.7603,19.59536 h 8 v -8 h -2.220703 v 5.787109 H 23.7603 Z"
id="rect4356-6"
inkscape:connector-curvature="0" />
<path
style="fill:#4c97ff;fill-opacity:1;stroke:none;stroke-width:1.25366771"
d="m 0.2260788,11.527481 v 8 h 8 v -2.220703 h -5.787109 v -5.779297 z"
id="rect4356-7"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

+36 -9
View File
@@ -23,21 +23,48 @@
padding: $space;
}
.stage-zoom-icon {
text-align: right;
.stage-size-row {
display: flex;
}
.stage-size-toggle-group {
display: flex;
margin-right: .2rem;
}
.stage-button {
display: block;
border: 1px solid $ui-pane-border;
border-radius: .25rem;
box-sizing: content-box;
width: 1.25rem;
height: 1.25rem;
padding: 0.375rem;
border-radius: 0.25rem;
user-select: none;
cursor: pointer;
transition: 0.2s ease-out;
}
.stage-zoom-icon:hover {
/* Scale icon image by 1.2, but keep background static */
width: 1.5rem;
height: 1.5rem;
padding: 0.25rem;
.stage-button-icon {
width: 100%;
height: 100%;
}
.stage-button-right {
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.stage-button-left {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.stage-button-active {
background: #FFF;
}
.stage-button-disabled {
opacity: .5;
cursor: auto;
}
+140 -64
View File
@@ -1,81 +1,157 @@
import classNames from 'classnames';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import PropTypes from 'prop-types';
import React from 'react';
import VM from 'scratch-vm';
import Box from '../box/box.jsx';
import Button from '../button/button.jsx';
import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx';
import Controls from '../../containers/controls.jsx';
import zoomIcon from './icon--zoom.svg';
import unzoomIcon from './icon--unzoom.svg';
import {STAGE_SIZES} from '../../reducers/stage-size';
import fullScreenIcon from './icon--fullscreen.svg';
import largeStageIcon from './icon--large-stage.svg';
import smallStageIcon from './icon--small-stage.svg';
import unFullScreenIcon from './icon--unfullscreen.svg';
import styles from './stage-header.css';
const messages = defineMessages({
largeStageSizeMessage: {
defaultMessage: 'Stage Size Toggle - Large',
description: 'Button to change stage size to large',
id: 'gui.gui.stageSizeLarge'
},
smallStageSizeMessage: {
defaultMessage: 'Stage Size Toggle - Small',
description: 'Button to change stage size to small',
id: 'gui.gui.stageSizeSmall'
},
fullStageSizeMessage: {
defaultMessage: 'Stage Size Toggle - Full Screen',
description: 'Button to change stage size to full screen',
id: 'gui.gui.stageSizeFull'
},
unFullStageSizeMessage: {
defaultMessage: 'Stage Size Toggle - Un-full screen',
description: 'Button to get out of full screen mode',
id: 'gui.gui.stageSizeUnFull'
}
});
const StageHeaderComponent = function (props) {
const {
className,
height,
isZoomed,
onUnzoom,
onZoom,
titleZoomIcon,
vm,
width,
...componentProps
stageSize,
isFullScreen,
onSetStageLarge,
onSetStageFull,
onSetStageUnFull,
vm
} = props;
return isZoomed === false ? (
<Box className={styles.stageHeaderWrapper}>
<Box
className={styles.stageMenuWrapper}
height={height}
width={width}
>
<Controls vm={vm} />
<img
className={classNames(
className,
styles.stageZoomIcon
)}
src={zoomIcon}
title={titleZoomIcon}
onClick={onZoom}
{...componentProps}
/>
let header = null;
if (isFullScreen) {
header = (
<Box className={styles.stageHeaderWrapperOverlay}>
<Box className={styles.stageMenuWrapper}>
<Controls vm={vm} />
<Button
className={classNames(
styles.stageButton,
styles.stageButtonActive
)}
onClick={onSetStageUnFull}
>
<img
alt={props.intl.formatMessage(messages.unFullStageSizeMessage)}
className={styles.stageButtonIcon}
src={unFullScreenIcon}
title="Full Screen Control"
/>
</Button>
</Box>
</Box>
</Box>
) : (
<Box className={styles.stageHeaderWrapperOverlay}>
<Box
className={styles.stageMenuWrapper}
height={'100%'}
width={'100%'}
>
<Controls vm={vm} />
<img
className={classNames(
className,
styles.stageZoomIcon
)}
src={unzoomIcon}
title={titleZoomIcon}
onClick={onUnzoom}
{...componentProps}
/>
);
} else {
header = (
<Box className={styles.stageHeaderWrapper}>
<Box className={styles.stageMenuWrapper}>
<Controls vm={vm} />
<div className={styles.stageSizeRow}>
<div className={styles.stageSizeToggleGroup}>
<ComingSoonTooltip
place="left"
tooltipId="small-stage-button"
>
<div
disabled
className={classNames(
styles.stageButton,
styles.stageButtonLeft,
styles.stageButtonDisabled
)}
role="button"
>
<img
disabled
alt={props.intl.formatMessage(messages.smallStageSizeMessage)}
className={styles.stageButtonIcon}
src={smallStageIcon}
/>
</div>
</ComingSoonTooltip>
<div>
<Button
className={classNames(
styles.stageButton,
styles.stageButtonRight,
{
[styles.stageButtonActive]: stageSize === STAGE_SIZES.large
}
)}
onClick={onSetStageLarge}
>
<img
alt={props.intl.formatMessage(messages.largeStageSizeMessage)}
className={styles.stageButtonIcon}
src={largeStageIcon}
/>
</Button>
</div>
</div>
<div>
<Button
className={styles.stageButton}
onClick={onSetStageFull}
>
<img
alt={props.intl.formatMessage(messages.fullStageSizeMessage)}
className={styles.stageButtonIcon}
src={fullScreenIcon}
title="Full Screen Control"
/>
</Button>
</div>
</div>
</Box>
</Box>
</Box>
);
);
}
return header;
};
StageHeaderComponent.propTypes = {
className: PropTypes.string,
height: PropTypes.number,
isZoomed: PropTypes.bool.isRequired,
onUnzoom: PropTypes.func.isRequired,
onZoom: PropTypes.func.isRequired,
titleZoomIcon: PropTypes.string,
vm: PropTypes.instanceOf(VM).isRequired,
width: PropTypes.number
intl: intlShape,
isFullScreen: PropTypes.bool.isRequired,
onSetStageFull: PropTypes.func.isRequired,
onSetStageLarge: PropTypes.func.isRequired,
onSetStageUnFull: PropTypes.func.isRequired,
stageSize: PropTypes.oneOf(Object.keys(STAGE_SIZES)).isRequired,
vm: PropTypes.instanceOf(VM).isRequired
};
StageHeaderComponent.defaultProps = {
width: 480,
height: 360,
titleZoomIcon: 'Zoom Control'
};
export default StageHeaderComponent;
export default injectIntl(StageHeaderComponent);
+7 -7
View File
@@ -13,7 +13,7 @@ const StageComponent = props => {
canvasRef,
height,
isColorPicking,
isZoomed,
isFullScreen,
width,
colorInfo,
onDeactivateColorPicker,
@@ -26,7 +26,7 @@ const StageComponent = props => {
let widthCorrectedAspect = width;
const spacingBorderAdjustment = 9;
const stageMenuHeightAdjustment = 40;
if (isZoomed) {
if (isFullScreen) {
heightCorrectedAspect = window.innerHeight - stageMenuHeightAdjustment - spacingBorderAdjustment;
widthCorrectedAspect = heightCorrectedAspect + (heightCorrectedAspect / 3);
if (widthCorrectedAspect > window.innerWidth) {
@@ -38,15 +38,15 @@ const StageComponent = props => {
<div>
<Box
className={classNames({
[styles.stageWrapper]: !isZoomed,
[styles.stageWrapperOverlay]: isZoomed,
[styles.withColorPicker]: !isZoomed && isColorPicking
[styles.stageWrapper]: !isFullScreen,
[styles.stageWrapperOverlay]: isFullScreen,
[styles.withColorPicker]: !isFullScreen && isColorPicking
})}
>
<Box
className={classNames(
styles.stage,
{[styles.stageOverlayContent]: isZoomed}
{[styles.stageOverlayContent]: isFullScreen}
)}
componentRef={canvasRef}
element="canvas"
@@ -95,7 +95,7 @@ StageComponent.propTypes = {
colorInfo: Loupe.propTypes.colorInfo,
height: PropTypes.number,
isColorPicking: PropTypes.bool,
isZoomed: PropTypes.bool.isRequired,
isFullScreen: PropTypes.bool.isRequired,
onDeactivateColorPicker: PropTypes.func,
onQuestionAnswered: PropTypes.func,
question: PropTypes.string,
+13 -5
View File
@@ -4,6 +4,8 @@ import React from 'react';
import {connect} from 'react-redux';
import ButtonComponent from '../components/button/button.jsx';
import {ComingSoonTooltip} from '../components/coming-soon/coming-soon.jsx';
class SaveButton extends React.Component {
constructor (props) {
@@ -38,12 +40,18 @@ class SaveButton extends React.Component {
...props
} = this.props;
return (
<ButtonComponent
onClick={this.handleClick}
{...props}
<ComingSoonTooltip
place="bottom"
tooltipId="save-button"
>
Save
</ButtonComponent>
<ButtonComponent
disabled
onClick={this.handleClick}
{...props}
>
Save
</ButtonComponent>
</ComingSoonTooltip>
);
}
}
+9 -8
View File
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import VM from 'scratch-vm';
import {setZoomed} from '../reducers/zoom';
import {setStageSize, setFullScreen, STAGE_SIZES} from '../reducers/stage-size';
import {connect} from 'react-redux';
@@ -22,19 +22,20 @@ class StageHeader extends React.Component {
}
StageHeader.propTypes = {
height: PropTypes.number,
isZoomed: PropTypes.bool,
vm: PropTypes.instanceOf(VM).isRequired,
width: PropTypes.number
stageSize: PropTypes.oneOf(Object.keys(STAGE_SIZES)),
vm: PropTypes.instanceOf(VM).isRequired
};
const mapStateToProps = state => ({
isZoomed: state.isZoomed
stageSize: state.stageSize.stageSize,
isFullScreen: state.stageSize.isFullScreen
});
const mapDispatchToProps = dispatch => ({
onZoom: () => dispatch(setZoomed(true)),
onUnzoom: () => dispatch(setZoomed(false))
onSetStageLarge: () => dispatch(setStageSize(STAGE_SIZES.large)),
onSetStageSmall: () => dispatch(setStageSize(STAGE_SIZES.small)),
onSetStageFull: () => dispatch(setFullScreen(true)),
onSetStageUnFull: () => dispatch(setFullScreen(false))
});
export default connect(
+3 -3
View File
@@ -57,7 +57,7 @@ class Stage extends React.Component {
this.props.height !== nextProps.height ||
this.props.isColorPicking !== nextProps.isColorPicking ||
this.state.colorInfo !== nextState.colorInfo ||
this.props.isZoomed !== nextProps.isZoomed ||
this.props.isFullScreen !== nextProps.isFullScreen ||
this.state.question !== nextState.question;
}
componentDidUpdate (prevProps) {
@@ -279,7 +279,7 @@ class Stage extends React.Component {
Stage.propTypes = {
height: PropTypes.number,
isColorPicking: PropTypes.bool,
isZoomed: PropTypes.bool,
isFullScreen: PropTypes.bool.isRequired,
onActivateColorPicker: PropTypes.func,
onDeactivateColorPicker: PropTypes.func,
vm: PropTypes.instanceOf(VM).isRequired,
@@ -288,7 +288,7 @@ Stage.propTypes = {
const mapStateToProps = state => ({
isColorPicking: state.colorPicker.active,
isZoomed: state.isZoomed
isFullScreen: state.stageSize.isFullScreen
});
const mapDispatchToProps = dispatch => ({
+2
View File
@@ -16,4 +16,6 @@ $sound-tertiary: #A63FA6;
$control-primary: #FFAB19;
$data-primary: #FF8C1A;
$form-border: #E9EEF2;
+2 -2
View File
@@ -8,14 +8,14 @@ import monitorLayoutReducer from './monitor-layout';
import targetReducer from './targets';
import toolboxReducer from './toolbox';
import vmReducer from './vm';
import zoomReducer from './zoom';
import stageSizeReducer from './stage-size';
import {ScratchPaintReducer} from 'scratch-paint';
export default combineReducers({
colorPicker: colorPickerReducer,
customProcedures: customProceduresReducer,
intl: intlReducer,
isZoomed: zoomReducer,
stageSize: stageSizeReducer,
modals: modalReducer,
monitors: monitorReducer,
monitorLayout: monitorLayoutReducer,
+55
View File
@@ -0,0 +1,55 @@
const SET_STAGE_SIZE = 'scratch-gui/StageSize/SET_STAGE_SIZE';
const SET_FULL_SCREEN = 'scratch-gui/StageSize/SET_FULL_SCREEN';
const initialState = {
isFullScreen: false,
stageSize: 'large'
};
// stage size constants
const STAGE_SIZES = {
small: 'small',
large: 'large'
};
const reducer = function (state, action) {
if (typeof state === 'undefined') state = initialState;
switch (action.type) {
case SET_STAGE_SIZE:
return {
isFullScreen: state.isFullScreen,
stageSize: action.stageSize
};
case SET_FULL_SCREEN:
return {
isFullScreen: action.isFullScreen,
stageSize: state.stageSize
};
default:
return state;
}
};
const setStageSize = function (stageSize) {
return {
type: SET_STAGE_SIZE,
stageSize: stageSize
};
};
// `isFullScreen` is a separate value because "stage size" does not
// actually apply to full screen mode, so they are treated as separate
// values to be assessed.
const setFullScreen = function (isFullScreen) {
return {
type: SET_FULL_SCREEN,
isFullScreen: isFullScreen
};
};
export {
reducer as default,
setStageSize,
setFullScreen,
STAGE_SIZES
};
-23
View File
@@ -1,23 +0,0 @@
const SET_ZOOMED = 'scratch-gui/Zoomed/SET_ZOOMED';
const defaultZoomed = false;
const initialState = defaultZoomed;
const reducer = function (state, action) {
if (typeof state === 'undefined') state = initialState;
switch (action.type) {
case SET_ZOOMED:
return action.isZoomed;
default:
return state;
}
};
const setZoomed = function (isZoomed) {
return {
type: SET_ZOOMED,
isZoomed: isZoomed
};
};
export {
reducer as default,
setZoomed
};
+4 -2
View File
@@ -143,7 +143,7 @@ describe('costumes, sounds and variables', () => {
const projectId = '96708228';
await loadUri(`${uri}#${projectId}`);
await new Promise(resolve => setTimeout(resolve, 2000));
await clickXpath('//img[@title="Zoom Control"]');
await clickXpath('//img[@title="Full Screen Control"]');
await clickXpath('//img[@title="Go"]');
await new Promise(resolve => setTimeout(resolve, 2000));
await clickXpath('//img[@title="Stop"]');
@@ -235,7 +235,9 @@ describe('costumes, sounds and variables', () => {
await expect(logs).toEqual([]);
});
test('Localization', async () => {
// Skipped temporarily while the language selector is marked as
// "Coming Soon"
test.skip('Localization', async () => {
await loadUri(uri);
await clickText('Blocks');
await clickText('Extensions');