82
82
@click =" goToPrevStep()"
83
83
style =" transform : rotate (180deg )"
84
84
>
85
- <CaretRightIcon />
85
+ <CaretRightSmallIcon />
86
86
</button >
87
87
<button
88
88
class =" next"
89
89
:class =" { loading: isLoading }"
90
90
:disabled =" disableNextStep"
91
91
@click =" !isLoading && goToNextStep()"
92
92
>
93
- <CaretRightIcon v-if =" !isLoading" />
93
+ <CaretRightSmallIcon v-if =" !isLoading" />
94
94
<CircleSpinner v-else class =" circle-spinner" />
95
95
</button >
96
96
</div >
102
102
import { useAccountStore } from ' @/stores/Account' ;
103
103
import { useNetworkStore } from ' @/stores/Network' ;
104
104
import { useTransactionsStore } from ' @/stores/Transactions' ;
105
- import { CircleSpinner } from ' @nimiq/vue-components' ;
105
+ import { CircleSpinner , CaretRightSmallIcon } from ' @nimiq/vue-components' ;
106
106
import {
107
107
computed ,
108
108
defineComponent ,
@@ -120,8 +120,8 @@ import {
120
120
getTour ,
121
121
MountedReturnFn , TourBroadcast , TourStep ,
122
122
TourStepIndex ,
123
+ WalletHTMLElements ,
123
124
} from ' ../lib/tour' ;
124
- import CaretRightIcon from ' ./icons/CaretRightIcon.vue' ;
125
125
import PartyConfettiIcon from ' ./icons/PartyConfettiIcon.vue' ;
126
126
import TourPreviousLeftArrowIcon from ' ./icons/TourPreviousLeftArrowIcon.vue' ;
127
127
@@ -217,7 +217,10 @@ export default defineComponent({
217
217
isLoading .value = false ;
218
218
219
219
window .addEventListener (' keyup' , _onKeyDown );
220
- window .addEventListener (' click' , _userClicked ());
220
+ setTimeout (() => {
221
+ window .addEventListener (' click' , _userClicked ());
222
+ }, 100 ); // avoid click event to be triggered by the setting button
223
+
221
224
// window.addEventListener('resize', _OnResize(_OnResizeEnd)); TODO
222
225
223
226
const app = document .querySelector (' #app' );
@@ -236,22 +239,26 @@ export default defineComponent({
236
239
// Dont allow user to interact with the page while it is loading
237
240
// But allow to end it
238
241
watch ([isLoading , disconnected ], async () => {
239
- const app = document .querySelector (' #app main' ) as HTMLDivElement ;
240
-
241
- if (isLoading .value || disconnected .value ) {
242
- app .setAttribute (' data-non-interactable' , ' ' );
243
- } else {
244
- app .removeAttribute (' data-non-interactable' );
245
- }
246
-
247
- // FIXME we should wait until the button is rendered and the we could
242
+ // TODO Avoid interaction with any of the elements when loading except tour elements (bar, manager and tooltip)
243
+ // const elements = Object.values(WalletHTMLElements).filter((e) => e);
244
+ // if (isLoading.value || disconnected.value) {
245
+ // elements.forEach((element) => {
246
+ // const el = document.querySelector(element);
247
+ // if (!el) return;
248
+ // el.setAttribute('data-non-interactable', 'loading');
249
+ // });
250
+ // } else {
251
+ // elements.forEach((element) => {
252
+ // const el = document.querySelector(element);
253
+ // if (!el) return;
254
+ // el.removeAttribute('data-non-interactable');
255
+ // });
256
+ // }
257
+
258
+ // FIXME we should wait until the buttons are rendered and the we could
248
259
// execute _toggleDisabledButtons but it is kind of random the amount of time
249
- // it takes to render the button. I don't know how to fix it.
250
-
251
- // Ensure that we disabled 'Receive Free NIM' button
252
- await sleep (500 ); // TODO
253
- // TODO Remove this code for the network, find other way
254
- // steps = Object.values(getTour(tourStore.tour?.name, context));
260
+ // it takes to render the button. I don't know how to fix it. Waiting 500ms works.
261
+ await sleep (500 );
255
262
_toggleDisabledButtons (steps [currentStep .value ]?.ui .disabledButtons , true );
256
263
});
257
264
@@ -274,7 +281,6 @@ export default defineComponent({
274
281
const { path : currentPath, ui : currentUI } = steps [currentStepIndex ]! ;
275
282
const { path : futurePath, ui : futureUI, lifecycle : futureLifecycle } = steps [futureStepIndex ]! ;
276
283
277
- isLoading .value = true ;
278
284
tour ! .stop ();
279
285
280
286
await sleep (500 );
@@ -294,6 +300,7 @@ export default defineComponent({
294
300
_toggleDisabledButtons (currentUI .disabledButtons , false );
295
301
_toggleDisabledButtons (futureUI .disabledButtons , true );
296
302
_addAttributes (futureUI , futureStepIndex );
303
+ await context .root .$nextTick ();
297
304
298
305
if (futurePath !== currentPath ) {
299
306
await sleep (500 );
@@ -302,14 +309,14 @@ export default defineComponent({
302
309
_removeAttributes (currentStepIndex );
303
310
304
311
tour ! .start (futureStepIndex .toString ());
312
+ await context .root .$nextTick ();
305
313
306
314
// FIXME Instead of doing tour!.end and tour!.start, we could also use .nextStep() or previsousStep()
307
315
// The problem with this solution is that some animations glitch the UI so it needs further
308
316
// investigation
309
317
// goingForward ? tour!.nextStep() : tour!.previousStep();
310
318
311
319
// mounted
312
- isLoading .value = false ;
313
320
disableNextStep .value = futureStepIndex >= nSteps .value - 1 || !! futureUI .isNextStepDisabled ;
314
321
315
322
unmounted = await futureLifecycle ?.mounted ?.({
@@ -338,6 +345,17 @@ export default defineComponent({
338
345
context .root .$on (' nimiq-tour-event' , (data : TourBroadcast ) => {
339
346
if (data .type === ' end-tour' ) endTour ();
340
347
});
348
+ context .root .$on (' nimiq-tour-event' , (data : TourBroadcast ) => {
349
+ if (data .type === ' clicked-outside-tour' ) {
350
+ const tourManager = document .querySelector (' .tour-control-bar' );
351
+ if (tourManager ) {
352
+ tourManager .classList .add (' flash' );
353
+ setTimeout (() => {
354
+ tourManager .classList .remove (' flash' );
355
+ }, 400 );
356
+ }
357
+ }
358
+ });
341
359
}
342
360
343
361
function _userClicked() {
@@ -382,12 +400,17 @@ export default defineComponent({
382
400
}
383
401
}
384
402
403
+ function _onScrollLockedElement(e : Event , el : Element ) {
404
+ e .preventDefault ();
405
+ el .scrollTop = 0 ;
406
+ }
385
407
function _addAttributes(
386
408
uiConfig : TourStep [' ui' ],
387
409
stepIndex : TourStepIndex ,
388
410
) {
389
411
const fadedElements = uiConfig .fadedElements || [];
390
412
const disabledElements = uiConfig .disabledElements || [];
413
+ const scrollLockedElements = uiConfig .scrollLockedElements || [];
391
414
392
415
disabledElements .filter ((e ) => e ).forEach ((element ) => {
393
416
const el = document .querySelector (element );
@@ -401,20 +424,33 @@ export default defineComponent({
401
424
el .setAttribute (' data-opacified' , stepIndex .toString ());
402
425
el .setAttribute (' data-non-interactable' , stepIndex .toString ());
403
426
});
427
+
428
+ scrollLockedElements .filter ((e ) => e ).forEach ((element ) => {
429
+ const el = document .querySelector (element );
430
+ if (! el ) return ;
431
+ el .setAttribute (' data-scroll-locked' , stepIndex .toString ());
432
+ // Avoid scrolling when tooltip is instantiated
433
+ el .addEventListener (' scroll' , (e ) => _onScrollLockedElement (e , el ));
434
+ el .scrollTop = 0 ;
435
+ });
404
436
}
405
437
406
438
function _removeAttributes(stepIndex : TourStepIndex ) {
407
- document
408
- .querySelectorAll (` [data-non-interactable="${stepIndex }"] ` )
439
+ document .querySelectorAll (` [data-non-interactable="${stepIndex }"] ` )
409
440
.forEach ((el ) => {
410
441
el .removeAttribute (' data-non-interactable' );
411
442
});
412
443
413
- document
414
- .querySelectorAll (` [data-opacified="${stepIndex }"] ` )
444
+ document .querySelectorAll (` [data-opacified="${stepIndex }"] ` )
415
445
.forEach ((el ) => {
416
446
el .removeAttribute (' data-opacified' );
417
447
});
448
+
449
+ document .querySelectorAll (` [data-scroll-locked="${stepIndex }"] ` )
450
+ .forEach ((el ) => {
451
+ el .removeAttribute (' data-scroll-locked' );
452
+ el .addEventListener (' scroll' , (e ) => _onScrollLockedElement (e , el ));
453
+ });
418
454
}
419
455
420
456
async function endTour(soft = false ) {
@@ -495,7 +531,7 @@ export default defineComponent({
495
531
// control bar
496
532
currentStep ,
497
533
nSteps ,
498
- isLoading: disconnected || isLoading ,
534
+ isLoading: computed (() => disconnected . value || isLoading . value ) ,
499
535
disableNextStep ,
500
536
501
537
// actions
@@ -509,7 +545,7 @@ export default defineComponent({
509
545
};
510
546
},
511
547
components: {
512
- CaretRightIcon ,
548
+ CaretRightSmallIcon ,
513
549
TourPreviousLeftArrowIcon ,
514
550
PartyConfettiIcon ,
515
551
CircleSpinner ,
@@ -530,24 +566,43 @@ export default defineComponent({
530
566
[data-tour-active ] [data-non-interactable ] * {
531
567
user-select : none !important ;
532
568
pointer-events : none !important ;
569
+ cursor : not-allowed ;
533
570
}
534
571
535
- [data-tour-active ]#app > * :not (.tour ):not (.tour-manager ) {
536
- cursor : not-allowed ;
572
+ [data-tour-active ] [data-scroll-locked ],
573
+ [data-tour-active ] [data-scroll-locked ] * {
574
+ overflow : hidden ;
537
575
}
538
576
539
- [data-tour-active ] button .highlighted {
577
+ [data-tour-active ] button .green-highlight {
540
578
background : linear-gradient (
541
579
274.28deg , rgba (255 , 255 , 255 , 0 ) 0% , rgba (255 , 255 , 255 , 0.2 ) 27.6% , rgba (255 , 255 , 255 , 0 ) 53.12% ,
542
580
rgba (255 , 255 , 255 , 0.2 ) 81.25% , rgba (255 , 255 , 255 , 0 ) 100%
543
- ),
544
- radial-gradient (100% 100% at 100% 100% , #41A38E 0% , #21BCA5 100% ) !important ;
581
+ ), var (--nimiq-green-bg ) !important ;
582
+ background-blend-mode : hard-light , normal !important ;
583
+ }
584
+
585
+ [data-tour-active ] button .gray-highlight {
586
+ background : linear-gradient (
587
+ 274.28deg , rgba (31 , 35 , 72 , 0 ) 0% , rgba (31 , 35 , 72 , 0.07 ) 27.6% , rgba (31 , 35 , 72 , 0 ) 53.12% ,
588
+ rgba (31 , 35 , 72 , 0.07 ) 81.25% , rgba (31 , 35 , 72 , 0 ) 100% ) !important ;
589
+ background-blend-mode : hard-light , normal !important ;
545
590
}
546
591
</style >
547
592
548
593
<style lang="scss" scoped>
549
594
.tour {
550
- position : relative ;
595
+ font-family : Mulish, Muli, -apple-system , BlinkMacSystemFont, " Segoe UI" ,
596
+ Roboto, Oxygen- Sans, Ubuntu, Cantarell, " Helvetica Neue" , sans-serif ;
597
+
598
+ position : absolute ;
599
+ width : 100vw ;
600
+ height : 100vh ;
601
+ pointer-events : none ;
602
+
603
+ > * {
604
+ pointer-events : initial ;
605
+ }
551
606
552
607
button {
553
608
width : min-content ;
@@ -571,6 +626,7 @@ export default defineComponent({
571
626
border-radius : 1rem ;
572
627
width : clamp (200px , 255px , calc (100vw - 2rem ));
573
628
padding : 2rem ;
629
+ z-index : 10 ;
574
630
575
631
.content {
576
632
display : flex ;
@@ -714,9 +770,7 @@ export default defineComponent({
714
770
grid-template-columns : 1fr 1fr 1fr ;
715
771
align-items : center ;
716
772
z-index : 6 ;
717
-
718
- // TODO Cannot use CSS variables here
719
- background : radial-gradient (100% 100% at 100% 100% , #265dd7 0% , #0582ca 100% );
773
+ background : var (--nimiq-light-blue-bg );
720
774
721
775
button {
722
776
padding : 1.4rem 1.6rem 1rem 1.6rem ;
@@ -749,14 +803,15 @@ export default defineComponent({
749
803
}
750
804
751
805
& .next {
752
- padding-left : 0.75rem ;
753
-
754
806
& .loading {
755
- padding-left : 0 ;
756
807
cursor : inherit ;
757
808
758
- & ::v- deep svg path: nth-child ( 1 ) {
809
+ & ::v- deep svg path {
759
810
stroke : var (--nimiq-white );
811
+
812
+ & :nth-child (2 ) {
813
+ opacity : 0.3 ;
814
+ }
760
815
}
761
816
}
762
817
}
@@ -772,6 +827,17 @@ export default defineComponent({
772
827
letter-spacing : -0.4px ;
773
828
font-variant-numeric : tabular-nums ;
774
829
}
830
+
831
+ }
832
+
833
+ [data-tour-active ] .flash {
834
+ animation : flash 0.4s ;
835
+ }
836
+
837
+ @keyframes flash {
838
+ from { background : var (--nimiq-light-blue-bg ); }
839
+ 50% { background : radial-gradient (100% 100% at bottom right , hsl (221 , 70% , 70% ), hsl (202 , 95% , 61% )); }
840
+ to { background : var (--nimiq-light-blue-bg ); }
775
841
}
776
842
777
843
.remove_me {
0 commit comments