1
1
import PropTypes from 'prop-types' ;
2
2
import React , { Fragment } from 'react' ;
3
+ import classNames from 'classnames' ;
3
4
import { FormattedMessage } from 'react-intl' ;
4
5
import Draggable from 'react-draggable' ;
5
6
6
7
import styles from './card.css' ;
7
8
9
+ import shrinkIcon from './icon--shrink.svg' ;
10
+ import expandIcon from './icon--expand.svg' ;
11
+
8
12
import rightArrow from './icon--next.svg' ;
9
13
import leftArrow from './icon--prev.svg' ;
10
14
@@ -14,8 +18,8 @@ import closeIcon from './icon--close.svg';
14
18
import { translateVideo } from '../../lib/libraries/decks/translate-video.js' ;
15
19
import { translateImage } from '../../lib/libraries/decks/translate-image.js' ;
16
20
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 ) } >
19
23
< div
20
24
className = { styles . allButton }
21
25
onClick = { onShowAll }
@@ -41,19 +45,42 @@ const CardHeader = ({onCloseCards, onShowAll, totalSteps, step}) => (
41
45
) ) }
42
46
</ div >
43
47
) : 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 >
57
84
</ div >
58
85
</ div >
59
86
) ;
@@ -107,13 +134,13 @@ ImageStep.propTypes = {
107
134
title : PropTypes . node . isRequired
108
135
} ;
109
136
110
- const NextPrevButtons = ( { isRtl, onNextStep, onPrevStep} ) => (
137
+ const NextPrevButtons = ( { isRtl, onNextStep, onPrevStep, expanded } ) => (
111
138
< Fragment >
112
139
{ onNextStep ? (
113
140
< div >
114
- < div className = { isRtl ? styles . leftCard : styles . rightCard } />
141
+ < div className = { expanded ? ( isRtl ? styles . leftCard : styles . rightCard ) : styles . hidden } />
115
142
< div
116
- className = { isRtl ? styles . leftButton : styles . rightButton }
143
+ className = { expanded ? ( isRtl ? styles . leftButton : styles . rightButton ) : styles . hidden }
117
144
onClick = { onNextStep }
118
145
>
119
146
< img
@@ -125,9 +152,9 @@ const NextPrevButtons = ({isRtl, onNextStep, onPrevStep}) => (
125
152
) : null }
126
153
{ onPrevStep ? (
127
154
< div >
128
- < div className = { isRtl ? styles . rightCard : styles . leftCard } />
155
+ < div className = { expanded ? ( isRtl ? styles . rightCard : styles . leftCard ) : styles . hidden } />
129
156
< div
130
- className = { isRtl ? styles . rightButton : styles . leftButton }
157
+ className = { expanded ? ( isRtl ? styles . rightButton : styles . leftButton ) : styles . hidden }
131
158
onClick = { onPrevStep }
132
159
>
133
160
< img
@@ -141,13 +168,16 @@ const NextPrevButtons = ({isRtl, onNextStep, onPrevStep}) => (
141
168
) ;
142
169
143
170
NextPrevButtons . propTypes = {
171
+ expanded : PropTypes . bool . isRequired ,
144
172
isRtl : PropTypes . bool ,
145
173
onNextStep : PropTypes . func ,
146
174
onPrevStep : PropTypes . func
147
175
} ;
148
176
CardHeader . propTypes = {
177
+ expanded : PropTypes . bool . isRequired ,
149
178
onCloseCards : PropTypes . func . isRequired ,
150
179
onShowAll : PropTypes . func . isRequired ,
180
+ onShrinkExpandCards : PropTypes . func . isRequired ,
151
181
step : PropTypes . number ,
152
182
totalSteps : PropTypes . number
153
183
} ;
@@ -219,78 +249,103 @@ const Cards = props => {
219
249
locale,
220
250
onActivateDeckFactory,
221
251
onCloseCards,
252
+ onShrinkExpandCards,
222
253
onDrag,
223
254
onStartDrag,
224
255
onEndDrag,
225
256
onShowAll,
226
257
onNextStep,
227
258
onPrevStep,
228
259
step,
260
+ expanded,
229
261
...posProps
230
262
} = props ;
231
263
let { x, y} = posProps ;
232
264
233
265
if ( activeDeckId === null ) return ;
234
266
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
+
235
275
if ( x === 0 && y === 0 ) {
236
276
// 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
239
280
// to near the bottom of the blocks palette to allow room to work above.
240
- const tallCardHeight = 385 ;
281
+ const tallCardHeight = 320 ;
241
282
const bottomMargin = 60 ; // To avoid overlapping the backpack region
242
- y = window . innerHeight - tallCardHeight - bottomMargin ;
283
+ y = window . innerHeight - tallCardHeight - bottomMargin - menuBarHeight ;
243
284
}
244
285
245
286
const steps = content [ activeDeckId ] . steps ;
246
287
247
288
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
+ } }
254
298
>
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 }
276
323
/>
277
324
) : (
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
+ />
285
345
</ div >
286
- < NextPrevButtons
287
- isRtl = { isRtl }
288
- onNextStep = { step < steps . length - 1 ? onNextStep : null }
289
- onPrevStep = { step > 0 ? onPrevStep : null }
290
- />
291
346
</ div >
292
- </ div >
293
- </ Draggable >
347
+ </ Draggable >
348
+ </ div >
294
349
) ;
295
350
} ;
296
351
@@ -309,6 +364,7 @@ Cards.propTypes = {
309
364
} )
310
365
} ) ,
311
366
dragging : PropTypes . bool . isRequired ,
367
+ expanded : PropTypes . bool . isRequired ,
312
368
isRtl : PropTypes . bool . isRequired ,
313
369
locale : PropTypes . string . isRequired ,
314
370
onActivateDeckFactory : PropTypes . func . isRequired ,
@@ -318,6 +374,7 @@ Cards.propTypes = {
318
374
onNextStep : PropTypes . func . isRequired ,
319
375
onPrevStep : PropTypes . func . isRequired ,
320
376
onShowAll : PropTypes . func ,
377
+ onShrinkExpandCards : PropTypes . func . isRequired ,
321
378
onStartDrag : PropTypes . func ,
322
379
step : PropTypes . number . isRequired ,
323
380
x : PropTypes . number ,
0 commit comments