From b5b88d3b8c2fa0aa96b1d5fb979aff264f0f6013 Mon Sep 17 00:00:00 2001 From: onmax Date: Wed, 2 Feb 2022 22:42:23 +0100 Subject: [PATCH] small tweaks and ui improvments --- src/components/Tour.vue | 148 +++++++++++++----- src/components/TourLargeScreenManager.vue | 55 ++++--- src/components/layouts/Settings.vue | 4 +- src/components/layouts/Sidebar.vue | 16 +- .../modals/DiscoverTheNimiqWalletModal.vue | 14 +- src/lib/tour/network/01_YourLocationStep.ts | 1 + src/lib/tour/network/02_BackboneNodeStep.ts | 1 + src/lib/tour/network/03_NetworkMetricsStep.ts | 1 + .../tour/network/04_NetworkCompletedStep.ts | 1 + .../tour/onboarding/01_FirstAddressStep.ts | 33 +++- .../tour/onboarding/02_TransactionListStep.ts | 28 ++-- .../onboarding/03_FirstTransactionStep.ts | 23 ++- .../tour/onboarding/04_BitcoinAddressStep.ts | 21 ++- .../tour/onboarding/05_WalletBalanceStep.ts | 29 +++- .../tour/onboarding/06_0_BackupAlertStep.ts | 14 +- src/lib/tour/onboarding/06_1_MenuIconStep.ts | 12 +- .../07_1_BackupOptionNotLargeScreenStep.ts | 11 +- .../07_2_BackupOptionLargeScreenStep.ts | 14 +- .../tour/onboarding/07_AccountOptionsStep.ts | 11 +- .../tour/onboarding/08_OnboardingCompleted.ts | 11 +- .../tour/onboarding/OnboardingTourTexts.ts | 17 +- src/lib/tour/onboarding/index.ts | 37 +++-- src/lib/tour/types.ts | 14 +- src/stores/Account.ts | 4 +- 24 files changed, 364 insertions(+), 156 deletions(-) diff --git a/src/components/Tour.vue b/src/components/Tour.vue index b061a252b..6726e1b29 100644 --- a/src/components/Tour.vue +++ b/src/components/Tour.vue @@ -82,7 +82,7 @@ @click="goToPrevStep()" style="transform: rotate(180deg)" > - + @@ -102,7 +102,7 @@ import { useAccountStore } from '@/stores/Account'; import { useNetworkStore } from '@/stores/Network'; import { useTransactionsStore } from '@/stores/Transactions'; -import { CircleSpinner } from '@nimiq/vue-components'; +import { CircleSpinner, CaretRightSmallIcon } from '@nimiq/vue-components'; import { computed, defineComponent, @@ -120,8 +120,8 @@ import { getTour, MountedReturnFn, TourBroadcast, TourStep, TourStepIndex, + WalletHTMLElements, } from '../lib/tour'; -import CaretRightIcon from './icons/CaretRightIcon.vue'; import PartyConfettiIcon from './icons/PartyConfettiIcon.vue'; import TourPreviousLeftArrowIcon from './icons/TourPreviousLeftArrowIcon.vue'; @@ -217,7 +217,10 @@ export default defineComponent({ isLoading.value = false; window.addEventListener('keyup', _onKeyDown); - window.addEventListener('click', _userClicked()); + setTimeout(() => { + window.addEventListener('click', _userClicked()); + }, 100); // avoid click event to be triggered by the setting button + // window.addEventListener('resize', _OnResize(_OnResizeEnd)); TODO const app = document.querySelector('#app'); @@ -236,22 +239,26 @@ export default defineComponent({ // Dont allow user to interact with the page while it is loading // But allow to end it watch([isLoading, disconnected], async () => { - const app = document.querySelector('#app main') as HTMLDivElement; - - if (isLoading.value || disconnected.value) { - app.setAttribute('data-non-interactable', ''); - } else { - app.removeAttribute('data-non-interactable'); - } - - // FIXME we should wait until the button is rendered and the we could + // TODO Avoid interaction with any of the elements when loading except tour elements (bar, manager and tooltip) + // const elements = Object.values(WalletHTMLElements).filter((e) => e); + // if (isLoading.value || disconnected.value) { + // elements.forEach((element) => { + // const el = document.querySelector(element); + // if (!el) return; + // el.setAttribute('data-non-interactable', 'loading'); + // }); + // } else { + // elements.forEach((element) => { + // const el = document.querySelector(element); + // if (!el) return; + // el.removeAttribute('data-non-interactable'); + // }); + // } + + // FIXME we should wait until the buttons are rendered and the we could // execute _toggleDisabledButtons but it is kind of random the amount of time - // it takes to render the button. I don't know how to fix it. - - // Ensure that we disabled 'Receive Free NIM' button - await sleep(500); // TODO - // TODO Remove this code for the network, find other way - // steps = Object.values(getTour(tourStore.tour?.name, context)); + // it takes to render the button. I don't know how to fix it. Waiting 500ms works. + await sleep(500); _toggleDisabledButtons(steps[currentStep.value]?.ui.disabledButtons, true); }); @@ -274,7 +281,6 @@ export default defineComponent({ const { path: currentPath, ui: currentUI } = steps[currentStepIndex]!; const { path: futurePath, ui: futureUI, lifecycle: futureLifecycle } = steps[futureStepIndex]!; - isLoading.value = true; tour!.stop(); await sleep(500); @@ -294,6 +300,7 @@ export default defineComponent({ _toggleDisabledButtons(currentUI.disabledButtons, false); _toggleDisabledButtons(futureUI.disabledButtons, true); _addAttributes(futureUI, futureStepIndex); + await context.root.$nextTick(); if (futurePath !== currentPath) { await sleep(500); @@ -302,6 +309,7 @@ export default defineComponent({ _removeAttributes(currentStepIndex); tour!.start(futureStepIndex.toString()); + await context.root.$nextTick(); // FIXME Instead of doing tour!.end and tour!.start, we could also use .nextStep() or previsousStep() // The problem with this solution is that some animations glitch the UI so it needs further @@ -309,7 +317,6 @@ export default defineComponent({ // goingForward ? tour!.nextStep() : tour!.previousStep(); // mounted - isLoading.value = false; disableNextStep.value = futureStepIndex >= nSteps.value - 1 || !!futureUI.isNextStepDisabled; unmounted = await futureLifecycle?.mounted?.({ @@ -338,6 +345,17 @@ export default defineComponent({ context.root.$on('nimiq-tour-event', (data: TourBroadcast) => { if (data.type === 'end-tour') endTour(); }); + context.root.$on('nimiq-tour-event', (data: TourBroadcast) => { + if (data.type === 'clicked-outside-tour') { + const tourManager = document.querySelector('.tour-control-bar'); + if (tourManager) { + tourManager.classList.add('flash'); + setTimeout(() => { + tourManager.classList.remove('flash'); + }, 400); + } + } + }); } function _userClicked() { @@ -382,12 +400,17 @@ export default defineComponent({ } } + function _onScrollLockedElement(e: Event, el: Element) { + e.preventDefault(); + el.scrollTop = 0; + } function _addAttributes( uiConfig: TourStep['ui'], stepIndex: TourStepIndex, ) { const fadedElements = uiConfig.fadedElements || []; const disabledElements = uiConfig.disabledElements || []; + const scrollLockedElements = uiConfig.scrollLockedElements || []; disabledElements.filter((e) => e).forEach((element) => { const el = document.querySelector(element); @@ -401,20 +424,33 @@ export default defineComponent({ el.setAttribute('data-opacified', stepIndex.toString()); el.setAttribute('data-non-interactable', stepIndex.toString()); }); + + scrollLockedElements.filter((e) => e).forEach((element) => { + const el = document.querySelector(element); + if (!el) return; + el.setAttribute('data-scroll-locked', stepIndex.toString()); + // Avoid scrolling when tooltip is instantiated + el.addEventListener('scroll', (e) => _onScrollLockedElement(e, el)); + el.scrollTop = 0; + }); } function _removeAttributes(stepIndex: TourStepIndex) { - document - .querySelectorAll(`[data-non-interactable="${stepIndex}"]`) + document.querySelectorAll(`[data-non-interactable="${stepIndex}"]`) .forEach((el) => { el.removeAttribute('data-non-interactable'); }); - document - .querySelectorAll(`[data-opacified="${stepIndex}"]`) + document.querySelectorAll(`[data-opacified="${stepIndex}"]`) .forEach((el) => { el.removeAttribute('data-opacified'); }); + + document.querySelectorAll(`[data-scroll-locked="${stepIndex}"]`) + .forEach((el) => { + el.removeAttribute('data-scroll-locked'); + el.addEventListener('scroll', (e) => _onScrollLockedElement(e, el)); + }); } async function endTour(soft = false) { @@ -495,7 +531,7 @@ export default defineComponent({ // control bar currentStep, nSteps, - isLoading: disconnected || isLoading, + isLoading: computed(() => disconnected.value || isLoading.value), disableNextStep, // actions @@ -509,7 +545,7 @@ export default defineComponent({ }; }, components: { - CaretRightIcon, + CaretRightSmallIcon, TourPreviousLeftArrowIcon, PartyConfettiIcon, CircleSpinner, @@ -530,24 +566,43 @@ export default defineComponent({ [data-tour-active] [data-non-interactable] * { user-select: none !important; pointer-events: none !important; + cursor: not-allowed; } -[data-tour-active]#app > *:not(.tour):not(.tour-manager) { - cursor: not-allowed; +[data-tour-active] [data-scroll-locked], +[data-tour-active] [data-scroll-locked] * { + overflow: hidden; } -[data-tour-active] button.highlighted { +[data-tour-active] button.green-highlight { background: linear-gradient( 274.28deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.2) 27.6%, rgba(255, 255, 255, 0) 53.12%, rgba(255, 255, 255, 0.2) 81.25%, rgba(255, 255, 255, 0) 100% - ), - radial-gradient(100% 100% at 100% 100%, #41A38E 0%, #21BCA5 100%) !important; + ), var(--nimiq-green-bg) !important; + background-blend-mode: hard-light, normal !important; +} + +[data-tour-active] button.gray-highlight { + background: linear-gradient( + 274.28deg, rgba(31, 35, 72, 0) 0%, rgba(31, 35, 72, 0.07) 27.6%, rgba(31, 35, 72, 0) 53.12%, + rgba(31, 35, 72, 0.07) 81.25%, rgba(31, 35, 72, 0) 100%) !important; + background-blend-mode: hard-light, normal !important; } diff --git a/src/components/layouts/Settings.vue b/src/components/layouts/Settings.vue index 08908f248..85479d92a 100644 --- a/src/components/layouts/Settings.vue +++ b/src/components/layouts/Settings.vue @@ -276,7 +276,7 @@ import { CircleSpinner } from '@nimiq/vue-components'; import { Portal } from '@linusborg/vue-simple-portal'; import { useAccountStore } from '@/stores/Account'; -import { TourName } from '@/lib/tour'; +import { TourName, TourOrigin } from '@/lib/tour'; import MenuIcon from '../icons/MenuIcon.vue'; import CrossCloseButton from '../CrossCloseButton.vue'; import CountryFlag from '../CountryFlag.vue'; @@ -375,7 +375,7 @@ export default defineComponent({ } function goToOnboardingTour() { - useAccountStore().setTour({ name: TourName.ONBOARDING, isANewUser: false }); + useAccountStore().setTour({ name: TourName.ONBOARDING, startedFrom: TourOrigin.SETTINGS }); context.root.$router.push('/'); } diff --git a/src/components/layouts/Sidebar.vue b/src/components/layouts/Sidebar.vue index a3c885b1b..a4820134c 100644 --- a/src/components/layouts/Sidebar.vue +++ b/src/components/layouts/Sidebar.vue @@ -16,8 +16,10 @@ Nimiq - - +
+ + +
@@ -230,10 +232,16 @@ export default defineComponent({ cursor: pointer; } -.announcement-box { +.panels { + display: flex; + flex-direction: column; + gap: 2rem; margin-bottom: 2.5rem; margin-top: 2rem; - align-self: stretch; + + ::v-deep .announcement-box, ::v-deep .tour-manager { + align-self: stretch; + } } .price-chart-wrapper { diff --git a/src/components/modals/DiscoverTheNimiqWalletModal.vue b/src/components/modals/DiscoverTheNimiqWalletModal.vue index 8bc34e1fb..3dc9ad8b0 100644 --- a/src/components/modals/DiscoverTheNimiqWalletModal.vue +++ b/src/components/modals/DiscoverTheNimiqWalletModal.vue @@ -2,7 +2,6 @@ -