Improve header components that need to be loaded in to display Skeleton and avoid layout shifting

This commit is contained in:
Rafael 2021-12-21 10:21:14 -03:00 committed by Thomas Zarebczan
parent 76147d89c6
commit 5c6fb9de66
4 changed files with 57 additions and 30 deletions

View file

@ -1,7 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doClearEmailEntry, doClearPasswordEntry } from 'redux/actions/user'; import { doClearEmailEntry, doClearPasswordEntry } from 'redux/actions/user';
import { doSignOut, doOpenModal } from 'redux/actions/app'; import { doSignOut, doOpenModal } from 'redux/actions/app';
import { formatCredits } from 'util/format-credits';
import { selectClientSetting } from 'redux/selectors/settings'; import { selectClientSetting } from 'redux/selectors/settings';
import { selectGetSyncErrorMessage } from 'redux/selectors/sync'; import { selectGetSyncErrorMessage } from 'redux/selectors/sync';
import { selectHasNavigated } from 'redux/selectors/app'; import { selectHasNavigated } from 'redux/selectors/app';
@ -17,8 +16,7 @@ const select = (state) => ({
emailToVerify: selectEmailToVerify(state), emailToVerify: selectEmailToVerify(state),
hasNavigated: selectHasNavigated(state), hasNavigated: selectHasNavigated(state),
hideBalance: selectClientSetting(state, SETTINGS.HIDE_BALANCE), hideBalance: selectClientSetting(state, SETTINGS.HIDE_BALANCE),
roundedBalance: formatCredits(selectTotalBalance(state), 2, true), totalBalance: selectTotalBalance(state),
roundedSpendableBalance: formatCredits(selectBalance(state), 2, true),
syncError: selectGetSyncErrorMessage(state), syncError: selectGetSyncErrorMessage(state),
user: selectUser(state), user: selectUser(state),
}); });

View file

@ -1,6 +1,7 @@
// @flow // @flow
import 'scss/component/_header.scss'; import 'scss/component/_header.scss';
import { formatCredits } from 'util/format-credits';
import { useIsMobile } from 'effects/use-screensize'; import { useIsMobile } from 'effects/use-screensize';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
@ -12,6 +13,7 @@ import HeaderProfileMenuButton from 'component/headerProfileMenuButton';
import Logo from 'component/logo'; import Logo from 'component/logo';
import NotificationBubble from 'component/notificationBubble'; import NotificationBubble from 'component/notificationBubble';
import React from 'react'; import React from 'react';
import Skeleton from '@mui/material/Skeleton';
import SkipNavigationButton from 'component/skipNavigationButton'; import SkipNavigationButton from 'component/skipNavigationButton';
import Tooltip from 'component/common/tooltip'; import Tooltip from 'component/common/tooltip';
import WunderBar from 'component/wunderbar'; import WunderBar from 'component/wunderbar';
@ -37,10 +39,9 @@ type Props = {
replace: (string) => void, replace: (string) => void,
}, },
isAbsoluteSideNavHidden: boolean, isAbsoluteSideNavHidden: boolean,
roundedBalance: string,
roundedSpendableBalance: string,
sidebarOpen: boolean, sidebarOpen: boolean,
syncError: ?string, syncError: ?string,
totalBalance?: number,
user: ?User, user: ?User,
clearEmailEntry: () => void, clearEmailEntry: () => void,
clearPasswordEntry: () => void, clearPasswordEntry: () => void,
@ -60,10 +61,9 @@ const Header = (props: Props) => {
hideCancel, hideCancel,
history, history,
isAbsoluteSideNavHidden, isAbsoluteSideNavHidden,
roundedBalance,
roundedSpendableBalance,
sidebarOpen, sidebarOpen,
syncError, syncError,
totalBalance,
user, user,
clearEmailEntry, clearEmailEntry,
clearPasswordEntry, clearPasswordEntry,
@ -90,6 +90,10 @@ const Header = (props: Props) => {
const canBackout = Boolean(backout); const canBackout = Boolean(backout);
const { backLabel, backNavDefault, title: backTitle, simpleTitle: simpleBackTitle } = backout || {}; const { backLabel, backNavDefault, title: backTitle, simpleTitle: simpleBackTitle } = backout || {};
const balanceLoading = totalBalance === undefined;
const roundedSpendableBalance = formatCredits(balance, 2, true);
const roundedTotalBalance = formatCredits(totalBalance, 2, true);
// Sign out if they click the "x" when they are on the password prompt // Sign out if they click the "x" when they are on the password prompt
const authHeaderAction = syncError && { onClick: signOut }; const authHeaderAction = syncError && { onClick: signOut };
const homeButtonNavigationProps = (isVerifyPage && {}) || (authHeader && authHeaderAction) || { navigate: '/' }; const homeButtonNavigationProps = (isVerifyPage && {}) || (authHeader && authHeaderAction) || { navigate: '/' };
@ -138,12 +142,16 @@ const Header = (props: Props) => {
} }
> >
<div> <div>
{balanceLoading ? (
<Skeleton variant="text" animation="wave" className="header__navigationItem--balanceLoading" />
) : (
<Button <Button
navigate={`/$/${PAGES.WALLET}`} navigate={`/$/${PAGES.WALLET}`}
className="button--file-action header__navigationItem--balance" className="button--file-action header__navigationItem--balance"
label={hideBalance || Number(roundedBalance) === 0 ? __('Your Wallet') : roundedBalance} label={hideBalance || Number(roundedTotalBalance) === 0 ? __('Your Wallet') : roundedTotalBalance}
icon={ICONS.LBC} icon={ICONS.LBC}
/> />
)}
</div> </div>
</Tooltip> </Tooltip>
)} )}

View file

@ -9,6 +9,7 @@ import classnames from 'classnames';
import HeaderMenuLink from 'component/common/header-menu-link'; import HeaderMenuLink from 'component/common/header-menu-link';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import React from 'react'; import React from 'react';
import Skeleton from '@mui/material/Skeleton';
type HeaderMenuButtonProps = { type HeaderMenuButtonProps = {
activeChannelClaim: ?ChannelClaim, activeChannelClaim: ?ChannelClaim,
@ -24,6 +25,9 @@ export default function HeaderProfileMenuButton(props: HeaderMenuButtonProps) {
return ( return (
<div className="header__buttons"> <div className="header__buttons">
<Menu> <Menu>
{activeChannelUrl === undefined ? (
<Skeleton variant="circular" animation="wave" className="header__navigationItem--iconSkeleton" />
) : (
<MenuButton <MenuButton
aria-label={__('Your account')} aria-label={__('Your account')}
title={__('Your account')} title={__('Your account')}
@ -38,6 +42,7 @@ export default function HeaderProfileMenuButton(props: HeaderMenuButtonProps) {
<Icon size={18} icon={ICONS.ACCOUNT} aria-hidden /> <Icon size={18} icon={ICONS.ACCOUNT} aria-hidden />
)} )}
</MenuButton> </MenuButton>
)}
<MenuList className="menu__list--header"> <MenuList className="menu__list--header">
<HeaderMenuLink page={PAGES.UPLOADS} icon={ICONS.PUBLISH} name={__('Uploads')} /> <HeaderMenuLink page={PAGES.UPLOADS} icon={ICONS.PUBLISH} name={__('Uploads')} />

View file

@ -90,9 +90,12 @@
.header__menu--right { .header__menu--right {
@extend .header__menu; @extend .header__menu;
justify-content: flex-end; justify-content: flex-end;
width: 10rem;
min-width: 10rem;
@media (max-width: $breakpoint-small) { @media (max-width: $breakpoint-small) {
max-width: 4rem; width: unset;
min-width: unset;
} }
} }
@ -155,6 +158,7 @@
.header__navigationItem--profilePic { .header__navigationItem--profilePic {
margin-right: var(--spacing-s); margin-right: var(--spacing-s);
background-color: var(--color-header-button);
.channel-thumbnail { .channel-thumbnail {
height: var(--height-button); height: var(--height-button);
@ -167,6 +171,12 @@
} }
} }
.header__navigationItem--iconSkeleton {
@extend .header__navigationItem--icon;
height: var(--height-button) !important;
width: var(--height-button) !important;
}
.header__navigationItem--balance { .header__navigationItem--balance {
@extend .header__navigationItem; @extend .header__navigationItem;
margin: 0 var(--spacing-s); margin: 0 var(--spacing-s);
@ -177,22 +187,28 @@
} }
} }
.header__navigationItem--balanceLoading {
margin: 0 var(--spacing-s);
width: 4rem;
background-color: var(--color-header-button);
}
.header__navigationItem--logo { .header__navigationItem--logo {
@extend .header__navigationItem; @extend .header__navigationItem;
height: 4rem;
display: flex; display: flex;
align-items: center; align-items: center;
margin-left: var(--spacing-m); margin-left: var(--spacing-m);
margin-right: var(--spacing-m); margin-right: var(--spacing-m);
color: var(--color-text); color: var(--color-text);
// move to lbry theme? // move to lbry theme?
.lbry-icon { .lbry-icon {
height: var(--height-button); height: var(--height-button);
width: var(--height-button); width: var(--height-button);
} }
@media (max-width: $breakpoint-small) { @media (max-width: $breakpoint-small) {
margin-right: var(--spacing-m); margin-right: var(--spacing-m);
height: 5rem;
.button__label { .button__label {
display: none; display: none;