diff --git a/src/components/cards/card.css b/src/components/cards/card.css index 28f79e176..dd8879482 100644 --- a/src/components/cards/card.css +++ b/src/components/cards/card.css @@ -2,10 +2,16 @@ @import "../../css/colors.css"; @import "../../css/z-index.css"; +.card-container-overlay { + position: fixed; + z-index: $z-index-card; +} + .card-container { position:absolute; z-index: $z-index-card; margin: 0.5rem 2rem; + min-width: 468px; } .left-card, .right-card { @@ -104,11 +110,38 @@ font-weight: bold; } +.header-buttons-hidden { + border-bottom: 0px; +} + +.header-buttons-right { + display: flex; + flex-direction: row; +} + +.header-buttons img { + margin-bottom: 2px; +} + +.shrink-expand-button { + cursor: pointer; + color: white; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 0.75rem; +} + +.shrink-expand-button:hover, .all-button:hover { + background-color: $ui-black-transparent; +} + .remove-button, .all-button { cursor: pointer; color: white; display: flex; - flex-direction: row; + flex-direction: column; justify-content: center; align-items: center; padding: 0.75rem; @@ -188,7 +221,7 @@ } .close-icon { - height: 1rem; + height: 1.25rem; margin: .125rem 0; /* To offset the .25rem difference in icon size */ } @@ -267,3 +300,7 @@ background: $ui-white; box-shadow: 0px 0px 0px 2px $ui-black-transparent; } + +.hidden { + display: none; +} diff --git a/src/components/cards/cards.jsx b/src/components/cards/cards.jsx index 48217a912..83e40bf49 100644 --- a/src/components/cards/cards.jsx +++ b/src/components/cards/cards.jsx @@ -1,10 +1,14 @@ import PropTypes from 'prop-types'; import React, {Fragment} from 'react'; +import classNames from 'classnames'; import {FormattedMessage} from 'react-intl'; import Draggable from 'react-draggable'; import styles from './card.css'; +import shrinkIcon from './icon--shrink.svg'; +import expandIcon from './icon--expand.svg'; + import rightArrow from './icon--next.svg'; import leftArrow from './icon--prev.svg'; @@ -14,8 +18,8 @@ import closeIcon from './icon--close.svg'; import {translateVideo} from '../../lib/libraries/decks/translate-video.js'; import {translateImage} from '../../lib/libraries/decks/translate-image.js'; -const CardHeader = ({onCloseCards, onShowAll, totalSteps, step}) => ( -
+const CardHeader = ({onCloseCards, onShrinkExpandCards, onShowAll, totalSteps, step, expanded}) => ( +
( ))}
) : null} -
- - +
+
+ + {expanded ? + : + + } +
+
+ + +
); @@ -107,13 +134,13 @@ ImageStep.propTypes = { title: PropTypes.node.isRequired }; -const NextPrevButtons = ({isRtl, onNextStep, onPrevStep}) => ( +const NextPrevButtons = ({isRtl, onNextStep, onPrevStep, expanded}) => ( {onNextStep ? (
-
+
( ) : null} {onPrevStep ? (
-
+
( ); NextPrevButtons.propTypes = { + expanded: PropTypes.bool.isRequired, isRtl: PropTypes.bool, onNextStep: PropTypes.func, onPrevStep: PropTypes.func }; CardHeader.propTypes = { + expanded: PropTypes.bool.isRequired, onCloseCards: PropTypes.func.isRequired, onShowAll: PropTypes.func.isRequired, + onShrinkExpandCards: PropTypes.func.isRequired, step: PropTypes.number, totalSteps: PropTypes.number }; @@ -219,6 +249,7 @@ const Cards = props => { locale, onActivateDeckFactory, onCloseCards, + onShrinkExpandCards, onDrag, onStartDrag, onEndDrag, @@ -226,71 +257,95 @@ const Cards = props => { onNextStep, onPrevStep, step, + expanded, ...posProps } = props; let {x, y} = posProps; if (activeDeckId === null) return; + // Tutorial cards need to calculate their own dragging bounds + // to allow for dragging the cards off the left, right and bottom + // edges of the workspace. + const cardHorizontalDragOffset = 400; // ~80% of card width + const cardVerticalDragOffset = expanded ? 257 : 0; // ~80% of card height, if expanded + const menuBarHeight = 48; // TODO: get pre-calculated from elsewhere? + const wideCardWidth = 500; + if (x === 0 && y === 0) { // initialize positions - x = isRtl ? -292 : 292; - // The tallest cards are about 385px high, and the default position is pinned + x = isRtl ? (-190 - wideCardWidth - cardHorizontalDragOffset) : 292; + x += cardHorizontalDragOffset; + // The tallest cards are about 320px high, and the default position is pinned // to near the bottom of the blocks palette to allow room to work above. - const tallCardHeight = 385; + const tallCardHeight = 320; const bottomMargin = 60; // To avoid overlapping the backpack region - y = window.innerHeight - tallCardHeight - bottomMargin; + y = window.innerHeight - tallCardHeight - bottomMargin - menuBarHeight; } const steps = content[activeDeckId].steps; return ( - -
-
- -
- {steps[step].deckIds ? ( - - ) : ( - steps[step].video ? ( - +
+
+ +
+ {steps[step].deckIds ? ( + ) : ( - - ) - )} - {steps[step].trackingPixel && steps[step].trackingPixel} + steps[step].video ? ( + + ) : ( + + ) + )} + {steps[step].trackingPixel && steps[step].trackingPixel} +
+ 0 ? onPrevStep : null} + />
- 0 ? onPrevStep : null} - />
-
- + +
); }; @@ -309,6 +364,7 @@ Cards.propTypes = { }) }), dragging: PropTypes.bool.isRequired, + expanded: PropTypes.bool.isRequired, isRtl: PropTypes.bool.isRequired, locale: PropTypes.string.isRequired, onActivateDeckFactory: PropTypes.func.isRequired, @@ -318,6 +374,7 @@ Cards.propTypes = { onNextStep: PropTypes.func.isRequired, onPrevStep: PropTypes.func.isRequired, onShowAll: PropTypes.func, + onShrinkExpandCards: PropTypes.func.isRequired, onStartDrag: PropTypes.func, step: PropTypes.number.isRequired, x: PropTypes.number, diff --git a/src/components/cards/icon--close.svg b/src/components/cards/icon--close.svg index a02ec1049..73c7b929f 100644 --- a/src/components/cards/icon--close.svg +++ b/src/components/cards/icon--close.svg @@ -1,17 +1,17 @@ - - General/Check Copy + + Extensions/Connection/Close Created with Sketch. - + - + - - + + diff --git a/src/components/cards/icon--expand.svg b/src/components/cards/icon--expand.svg new file mode 100644 index 000000000..d8a01734f --- /dev/null +++ b/src/components/cards/icon--expand.svg @@ -0,0 +1,18 @@ + + + + Tutorials/Expand + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/cards/icon--shrink.svg b/src/components/cards/icon--shrink.svg new file mode 100644 index 000000000..2d630d4ee --- /dev/null +++ b/src/components/cards/icon--shrink.svg @@ -0,0 +1,18 @@ + + + + Tutorials/Shink + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/containers/cards.jsx b/src/containers/cards.jsx index e75b1e129..751d523f7 100644 --- a/src/containers/cards.jsx +++ b/src/containers/cards.jsx @@ -5,6 +5,7 @@ import React from 'react'; import { activateDeck, closeCards, + shrinkExpandCards, nextStep, prevStep, dragCard, @@ -46,6 +47,7 @@ const mapStateToProps = state => ({ content: state.scratchGui.cards.content, activeDeckId: state.scratchGui.cards.activeDeckId, step: state.scratchGui.cards.step, + expanded: state.scratchGui.cards.expanded, x: state.scratchGui.cards.x, y: state.scratchGui.cards.y, isRtl: state.locales.isRtl, @@ -60,6 +62,7 @@ const mapDispatchToProps = dispatch => ({ dispatch(closeCards()); }, onCloseCards: () => dispatch(closeCards()), + onShrinkExpandCards: () => dispatch(shrinkExpandCards()), onNextStep: () => dispatch(nextStep()), onPrevStep: () => dispatch(prevStep()), onDrag: (e_, data) => dispatch(dragCard(data.x, data.y)), diff --git a/src/reducers/cards.js b/src/reducers/cards.js index 37319cbea..373130442 100644 --- a/src/reducers/cards.js +++ b/src/reducers/cards.js @@ -3,6 +3,7 @@ import analytics from '../lib/analytics'; import decks from '../lib/libraries/decks/index.jsx'; const CLOSE_CARDS = 'scratch-gui/cards/CLOSE_CARDS'; +const SHRINK_EXPAND_CARDS = 'scratch-gui/cards/SHRINK_EXPAND_CARDS'; const VIEW_CARDS = 'scratch-gui/cards/VIEW_CARDS'; const ACTIVATE_DECK = 'scratch-gui/cards/ACTIVATE_DECK'; const NEXT_STEP = 'scratch-gui/cards/NEXT_STEP'; @@ -18,6 +19,7 @@ const initialState = { step: 0, x: 0, y: 0, + expanded: true, dragging: false }; @@ -28,6 +30,10 @@ const reducer = function (state, action) { return Object.assign({}, state, { visible: false }); + case SHRINK_EXPAND_CARDS: + return Object.assign({}, state, { + expanded: !state.expanded + }); case VIEW_CARDS: return Object.assign({}, state, { visible: true @@ -36,6 +42,9 @@ const reducer = function (state, action) { return Object.assign({}, state, { activeDeckId: action.activeDeckId, step: 0, + x: 0, + y: 0, + expanded: true, visible: true }); case NEXT_STEP: @@ -92,6 +101,10 @@ const closeCards = function () { return {type: CLOSE_CARDS}; }; +const shrinkExpandCards = function () { + return {type: SHRINK_EXPAND_CARDS}; +}; + const nextStep = function () { return {type: NEXT_STEP}; }; @@ -118,6 +131,7 @@ export { activateDeck, viewCards, closeCards, + shrinkExpandCards, nextStep, prevStep, dragCard, diff --git a/src/reducers/gui.js b/src/reducers/gui.js index 071f9d93b..9024b4742 100644 --- a/src/reducers/gui.js +++ b/src/reducers/gui.js @@ -107,6 +107,7 @@ const initTutorialCard = function (currentState, deckId) { visible: true, content: decks, activeDeckId: deckId, + expanded: true, step: 0, x: 0, y: 0,