Skip to content

Commit f8b3e49

Browse files
authored
Merge pull request scratchfoundation#4731 from evhan55/feature/4670
Add shrink/expand and new fencing feature to tutorial cards
2 parents 7f06f55 + cca701e commit f8b3e49

File tree

8 files changed

+221
-73
lines changed

8 files changed

+221
-73
lines changed

src/components/cards/card.css

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@
22
@import "../../css/colors.css";
33
@import "../../css/z-index.css";
44

5+
.card-container-overlay {
6+
position: fixed;
7+
z-index: $z-index-card;
8+
}
9+
510
.card-container {
611
position:absolute;
712
z-index: $z-index-card;
813
margin: 0.5rem 2rem;
14+
min-width: 468px;
915
}
1016

1117
.left-card, .right-card {
@@ -104,11 +110,38 @@
104110
font-weight: bold;
105111
}
106112

113+
.header-buttons-hidden {
114+
border-bottom: 0px;
115+
}
116+
117+
.header-buttons-right {
118+
display: flex;
119+
flex-direction: row;
120+
}
121+
122+
.header-buttons img {
123+
margin-bottom: 2px;
124+
}
125+
126+
.shrink-expand-button {
127+
cursor: pointer;
128+
color: white;
129+
display: flex;
130+
flex-direction: column;
131+
justify-content: center;
132+
align-items: center;
133+
padding: 0.75rem;
134+
}
135+
136+
.shrink-expand-button:hover, .all-button:hover {
137+
background-color: $ui-black-transparent;
138+
}
139+
107140
.remove-button, .all-button {
108141
cursor: pointer;
109142
color: white;
110143
display: flex;
111-
flex-direction: row;
144+
flex-direction: column;
112145
justify-content: center;
113146
align-items: center;
114147
padding: 0.75rem;
@@ -188,7 +221,7 @@
188221
}
189222

190223
.close-icon {
191-
height: 1rem;
224+
height: 1.25rem;
192225
margin: .125rem 0; /* To offset the .25rem difference in icon size */
193226
}
194227

@@ -267,3 +300,7 @@
267300
background: $ui-white;
268301
box-shadow: 0px 0px 0px 2px $ui-black-transparent;
269302
}
303+
304+
.hidden {
305+
display: none;
306+
}

src/components/cards/cards.jsx

Lines changed: 122 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import PropTypes from 'prop-types';
22
import React, {Fragment} from 'react';
3+
import classNames from 'classnames';
34
import {FormattedMessage} from 'react-intl';
45
import Draggable from 'react-draggable';
56

67
import styles from './card.css';
78

9+
import shrinkIcon from './icon--shrink.svg';
10+
import expandIcon from './icon--expand.svg';
11+
812
import rightArrow from './icon--next.svg';
913
import leftArrow from './icon--prev.svg';
1014

@@ -14,8 +18,8 @@ import closeIcon from './icon--close.svg';
1418
import {translateVideo} from '../../lib/libraries/decks/translate-video.js';
1519
import {translateImage} from '../../lib/libraries/decks/translate-image.js';
1620

17-
const CardHeader = ({onCloseCards, onShowAll, totalSteps, step}) => (
18-
<div className={styles.headerButtons}>
21+
const CardHeader = ({onCloseCards, onShrinkExpandCards, onShowAll, totalSteps, step, expanded}) => (
22+
<div className={expanded ? styles.headerButtons : classNames(styles.headerButtons, styles.headerButtonsHidden)}>
1923
<div
2024
className={styles.allButton}
2125
onClick={onShowAll}
@@ -41,19 +45,42 @@ const CardHeader = ({onCloseCards, onShowAll, totalSteps, step}) => (
4145
))}
4246
</div>
4347
) : null}
44-
<div
45-
className={styles.removeButton}
46-
onClick={onCloseCards}
47-
>
48-
<FormattedMessage
49-
defaultMessage="Close"
50-
description="Title for button to close how-to card"
51-
id="gui.cards.close"
52-
/>
53-
<img
54-
className={styles.closeIcon}
55-
src={closeIcon}
56-
/>
48+
<div className={styles.headerButtonsRight}>
49+
<div
50+
className={styles.shrinkExpandButton}
51+
onClick={onShrinkExpandCards}
52+
>
53+
<img
54+
draggable={false}
55+
src={expanded ? shrinkIcon : expandIcon}
56+
/>
57+
{expanded ?
58+
<FormattedMessage
59+
defaultMessage="Shrink"
60+
description="Title for button to shrink how-to card"
61+
id="gui.cards.shrink"
62+
/> :
63+
<FormattedMessage
64+
defaultMessage="Expand"
65+
description="Title for button to expand how-to card"
66+
id="gui.cards.expand"
67+
/>
68+
}
69+
</div>
70+
<div
71+
className={styles.removeButton}
72+
onClick={onCloseCards}
73+
>
74+
<img
75+
className={styles.closeIcon}
76+
src={closeIcon}
77+
/>
78+
<FormattedMessage
79+
defaultMessage="Close"
80+
description="Title for button to close how-to card"
81+
id="gui.cards.close"
82+
/>
83+
</div>
5784
</div>
5885
</div>
5986
);
@@ -107,13 +134,13 @@ ImageStep.propTypes = {
107134
title: PropTypes.node.isRequired
108135
};
109136

110-
const NextPrevButtons = ({isRtl, onNextStep, onPrevStep}) => (
137+
const NextPrevButtons = ({isRtl, onNextStep, onPrevStep, expanded}) => (
111138
<Fragment>
112139
{onNextStep ? (
113140
<div>
114-
<div className={isRtl ? styles.leftCard : styles.rightCard} />
141+
<div className={expanded ? (isRtl ? styles.leftCard : styles.rightCard) : styles.hidden} />
115142
<div
116-
className={isRtl ? styles.leftButton : styles.rightButton}
143+
className={expanded ? (isRtl ? styles.leftButton : styles.rightButton) : styles.hidden}
117144
onClick={onNextStep}
118145
>
119146
<img
@@ -125,9 +152,9 @@ const NextPrevButtons = ({isRtl, onNextStep, onPrevStep}) => (
125152
) : null}
126153
{onPrevStep ? (
127154
<div>
128-
<div className={isRtl ? styles.rightCard : styles.leftCard} />
155+
<div className={expanded ? (isRtl ? styles.rightCard : styles.leftCard) : styles.hidden} />
129156
<div
130-
className={isRtl ? styles.rightButton : styles.leftButton}
157+
className={expanded ? (isRtl ? styles.rightButton : styles.leftButton) : styles.hidden}
131158
onClick={onPrevStep}
132159
>
133160
<img
@@ -141,13 +168,16 @@ const NextPrevButtons = ({isRtl, onNextStep, onPrevStep}) => (
141168
);
142169

143170
NextPrevButtons.propTypes = {
171+
expanded: PropTypes.bool.isRequired,
144172
isRtl: PropTypes.bool,
145173
onNextStep: PropTypes.func,
146174
onPrevStep: PropTypes.func
147175
};
148176
CardHeader.propTypes = {
177+
expanded: PropTypes.bool.isRequired,
149178
onCloseCards: PropTypes.func.isRequired,
150179
onShowAll: PropTypes.func.isRequired,
180+
onShrinkExpandCards: PropTypes.func.isRequired,
151181
step: PropTypes.number,
152182
totalSteps: PropTypes.number
153183
};
@@ -219,78 +249,103 @@ const Cards = props => {
219249
locale,
220250
onActivateDeckFactory,
221251
onCloseCards,
252+
onShrinkExpandCards,
222253
onDrag,
223254
onStartDrag,
224255
onEndDrag,
225256
onShowAll,
226257
onNextStep,
227258
onPrevStep,
228259
step,
260+
expanded,
229261
...posProps
230262
} = props;
231263
let {x, y} = posProps;
232264

233265
if (activeDeckId === null) return;
234266

267+
// Tutorial cards need to calculate their own dragging bounds
268+
// to allow for dragging the cards off the left, right and bottom
269+
// edges of the workspace.
270+
const cardHorizontalDragOffset = 400; // ~80% of card width
271+
const cardVerticalDragOffset = expanded ? 257 : 0; // ~80% of card height, if expanded
272+
const menuBarHeight = 48; // TODO: get pre-calculated from elsewhere?
273+
const wideCardWidth = 500;
274+
235275
if (x === 0 && y === 0) {
236276
// initialize positions
237-
x = isRtl ? -292 : 292;
238-
// The tallest cards are about 385px high, and the default position is pinned
277+
x = isRtl ? (-190 - wideCardWidth - cardHorizontalDragOffset) : 292;
278+
x += cardHorizontalDragOffset;
279+
// The tallest cards are about 320px high, and the default position is pinned
239280
// to near the bottom of the blocks palette to allow room to work above.
240-
const tallCardHeight = 385;
281+
const tallCardHeight = 320;
241282
const bottomMargin = 60; // To avoid overlapping the backpack region
242-
y = window.innerHeight - tallCardHeight - bottomMargin;
283+
y = window.innerHeight - tallCardHeight - bottomMargin - menuBarHeight;
243284
}
244285

245286
const steps = content[activeDeckId].steps;
246287

247288
return (
248-
<Draggable
249-
bounds="parent"
250-
position={{x: x, y: y}}
251-
onDrag={onDrag}
252-
onStart={onStartDrag}
253-
onStop={onEndDrag}
289+
// Custom overlay to act as the bounding parent for the draggable, using values from above
290+
<div
291+
className={styles.cardContainerOverlay}
292+
style={{
293+
width: `${window.innerWidth + (2 * cardHorizontalDragOffset)}px`,
294+
height: `${window.innerHeight - menuBarHeight + cardVerticalDragOffset}px`,
295+
top: `${menuBarHeight}px`,
296+
left: `${-cardHorizontalDragOffset}px`
297+
}}
254298
>
255-
<div className={styles.cardContainer}>
256-
<div className={styles.card}>
257-
<CardHeader
258-
step={step}
259-
totalSteps={steps.length}
260-
onCloseCards={onCloseCards}
261-
onShowAll={onShowAll}
262-
/>
263-
<div className={styles.stepBody}>
264-
{steps[step].deckIds ? (
265-
<PreviewsStep
266-
content={content}
267-
deckIds={steps[step].deckIds}
268-
onActivateDeckFactory={onActivateDeckFactory}
269-
onShowAll={onShowAll}
270-
/>
271-
) : (
272-
steps[step].video ? (
273-
<VideoStep
274-
dragging={dragging}
275-
video={translateVideo(steps[step].video, locale)}
299+
<Draggable
300+
bounds="parent"
301+
position={{x: x, y: y}}
302+
onDrag={onDrag}
303+
onStart={onStartDrag}
304+
onStop={onEndDrag}
305+
>
306+
<div className={styles.cardContainer}>
307+
<div className={styles.card}>
308+
<CardHeader
309+
expanded={expanded}
310+
step={step}
311+
totalSteps={steps.length}
312+
onCloseCards={onCloseCards}
313+
onShowAll={onShowAll}
314+
onShrinkExpandCards={onShrinkExpandCards}
315+
/>
316+
<div className={expanded ? styles.stepBody : styles.hidden}>
317+
{steps[step].deckIds ? (
318+
<PreviewsStep
319+
content={content}
320+
deckIds={steps[step].deckIds}
321+
onActivateDeckFactory={onActivateDeckFactory}
322+
onShowAll={onShowAll}
276323
/>
277324
) : (
278-
<ImageStep
279-
image={translateImage(steps[step].image, locale)}
280-
title={steps[step].title}
281-
/>
282-
)
283-
)}
284-
{steps[step].trackingPixel && steps[step].trackingPixel}
325+
steps[step].video ? (
326+
<VideoStep
327+
dragging={dragging}
328+
video={translateVideo(steps[step].video, locale)}
329+
/>
330+
) : (
331+
<ImageStep
332+
image={translateImage(steps[step].image, locale)}
333+
title={steps[step].title}
334+
/>
335+
)
336+
)}
337+
{steps[step].trackingPixel && steps[step].trackingPixel}
338+
</div>
339+
<NextPrevButtons
340+
expanded={expanded}
341+
isRtl={isRtl}
342+
onNextStep={step < steps.length - 1 ? onNextStep : null}
343+
onPrevStep={step > 0 ? onPrevStep : null}
344+
/>
285345
</div>
286-
<NextPrevButtons
287-
isRtl={isRtl}
288-
onNextStep={step < steps.length - 1 ? onNextStep : null}
289-
onPrevStep={step > 0 ? onPrevStep : null}
290-
/>
291346
</div>
292-
</div>
293-
</Draggable>
347+
</Draggable>
348+
</div>
294349
);
295350
};
296351

@@ -309,6 +364,7 @@ Cards.propTypes = {
309364
})
310365
}),
311366
dragging: PropTypes.bool.isRequired,
367+
expanded: PropTypes.bool.isRequired,
312368
isRtl: PropTypes.bool.isRequired,
313369
locale: PropTypes.string.isRequired,
314370
onActivateDeckFactory: PropTypes.func.isRequired,
@@ -318,6 +374,7 @@ Cards.propTypes = {
318374
onNextStep: PropTypes.func.isRequired,
319375
onPrevStep: PropTypes.func.isRequired,
320376
onShowAll: PropTypes.func,
377+
onShrinkExpandCards: PropTypes.func.isRequired,
321378
onStartDrag: PropTypes.func,
322379
step: PropTypes.number.isRequired,
323380
x: PropTypes.number,

src/components/cards/icon--close.svg

Lines changed: 6 additions & 6 deletions
Loading

0 commit comments

Comments
 (0)