Improve header components that need to be loaded in to display Skeleton and avoid layout shifting
This commit is contained in:
parent
76147d89c6
commit
5c6fb9de66
4 changed files with 57 additions and 30 deletions
|
@ -1,7 +1,6 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doClearEmailEntry, doClearPasswordEntry } from 'redux/actions/user';
|
||||
import { doSignOut, doOpenModal } from 'redux/actions/app';
|
||||
import { formatCredits } from 'util/format-credits';
|
||||
import { selectClientSetting } from 'redux/selectors/settings';
|
||||
import { selectGetSyncErrorMessage } from 'redux/selectors/sync';
|
||||
import { selectHasNavigated } from 'redux/selectors/app';
|
||||
|
@ -17,8 +16,7 @@ const select = (state) => ({
|
|||
emailToVerify: selectEmailToVerify(state),
|
||||
hasNavigated: selectHasNavigated(state),
|
||||
hideBalance: selectClientSetting(state, SETTINGS.HIDE_BALANCE),
|
||||
roundedBalance: formatCredits(selectTotalBalance(state), 2, true),
|
||||
roundedSpendableBalance: formatCredits(selectBalance(state), 2, true),
|
||||
totalBalance: selectTotalBalance(state),
|
||||
syncError: selectGetSyncErrorMessage(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import 'scss/component/_header.scss';
|
||||
|
||||
import { formatCredits } from 'util/format-credits';
|
||||
import { useIsMobile } from 'effects/use-screensize';
|
||||
import { withRouter } from 'react-router';
|
||||
import * as ICONS from 'constants/icons';
|
||||
|
@ -12,6 +13,7 @@ import HeaderProfileMenuButton from 'component/headerProfileMenuButton';
|
|||
import Logo from 'component/logo';
|
||||
import NotificationBubble from 'component/notificationBubble';
|
||||
import React from 'react';
|
||||
import Skeleton from '@mui/material/Skeleton';
|
||||
import SkipNavigationButton from 'component/skipNavigationButton';
|
||||
import Tooltip from 'component/common/tooltip';
|
||||
import WunderBar from 'component/wunderbar';
|
||||
|
@ -37,10 +39,9 @@ type Props = {
|
|||
replace: (string) => void,
|
||||
},
|
||||
isAbsoluteSideNavHidden: boolean,
|
||||
roundedBalance: string,
|
||||
roundedSpendableBalance: string,
|
||||
sidebarOpen: boolean,
|
||||
syncError: ?string,
|
||||
totalBalance?: number,
|
||||
user: ?User,
|
||||
clearEmailEntry: () => void,
|
||||
clearPasswordEntry: () => void,
|
||||
|
@ -60,10 +61,9 @@ const Header = (props: Props) => {
|
|||
hideCancel,
|
||||
history,
|
||||
isAbsoluteSideNavHidden,
|
||||
roundedBalance,
|
||||
roundedSpendableBalance,
|
||||
sidebarOpen,
|
||||
syncError,
|
||||
totalBalance,
|
||||
user,
|
||||
clearEmailEntry,
|
||||
clearPasswordEntry,
|
||||
|
@ -90,6 +90,10 @@ const Header = (props: Props) => {
|
|||
const canBackout = Boolean(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
|
||||
const authHeaderAction = syncError && { onClick: signOut };
|
||||
const homeButtonNavigationProps = (isVerifyPage && {}) || (authHeader && authHeaderAction) || { navigate: '/' };
|
||||
|
@ -138,12 +142,16 @@ const Header = (props: Props) => {
|
|||
}
|
||||
>
|
||||
<div>
|
||||
<Button
|
||||
navigate={`/$/${PAGES.WALLET}`}
|
||||
className="button--file-action header__navigationItem--balance"
|
||||
label={hideBalance || Number(roundedBalance) === 0 ? __('Your Wallet') : roundedBalance}
|
||||
icon={ICONS.LBC}
|
||||
/>
|
||||
{balanceLoading ? (
|
||||
<Skeleton variant="text" animation="wave" className="header__navigationItem--balanceLoading" />
|
||||
) : (
|
||||
<Button
|
||||
navigate={`/$/${PAGES.WALLET}`}
|
||||
className="button--file-action header__navigationItem--balance"
|
||||
label={hideBalance || Number(roundedTotalBalance) === 0 ? __('Your Wallet') : roundedTotalBalance}
|
||||
icon={ICONS.LBC}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
|
|
@ -9,6 +9,7 @@ import classnames from 'classnames';
|
|||
import HeaderMenuLink from 'component/common/header-menu-link';
|
||||
import Icon from 'component/common/icon';
|
||||
import React from 'react';
|
||||
import Skeleton from '@mui/material/Skeleton';
|
||||
|
||||
type HeaderMenuButtonProps = {
|
||||
activeChannelClaim: ?ChannelClaim,
|
||||
|
@ -24,20 +25,24 @@ export default function HeaderProfileMenuButton(props: HeaderMenuButtonProps) {
|
|||
return (
|
||||
<div className="header__buttons">
|
||||
<Menu>
|
||||
<MenuButton
|
||||
aria-label={__('Your account')}
|
||||
title={__('Your account')}
|
||||
className={classnames('header__navigationItem', {
|
||||
'header__navigationItem--icon': !activeChannelUrl,
|
||||
'header__navigationItem--profilePic': activeChannelUrl,
|
||||
})}
|
||||
>
|
||||
{activeChannelUrl ? (
|
||||
<ChannelThumbnail uri={activeChannelUrl} small noLazyLoad />
|
||||
) : (
|
||||
<Icon size={18} icon={ICONS.ACCOUNT} aria-hidden />
|
||||
)}
|
||||
</MenuButton>
|
||||
{activeChannelUrl === undefined ? (
|
||||
<Skeleton variant="circular" animation="wave" className="header__navigationItem--iconSkeleton" />
|
||||
) : (
|
||||
<MenuButton
|
||||
aria-label={__('Your account')}
|
||||
title={__('Your account')}
|
||||
className={classnames('header__navigationItem', {
|
||||
'header__navigationItem--icon': !activeChannelUrl,
|
||||
'header__navigationItem--profilePic': activeChannelUrl,
|
||||
})}
|
||||
>
|
||||
{activeChannelUrl ? (
|
||||
<ChannelThumbnail uri={activeChannelUrl} small noLazyLoad />
|
||||
) : (
|
||||
<Icon size={18} icon={ICONS.ACCOUNT} aria-hidden />
|
||||
)}
|
||||
</MenuButton>
|
||||
)}
|
||||
|
||||
<MenuList className="menu__list--header">
|
||||
<HeaderMenuLink page={PAGES.UPLOADS} icon={ICONS.PUBLISH} name={__('Uploads')} />
|
||||
|
|
|
@ -90,9 +90,12 @@
|
|||
.header__menu--right {
|
||||
@extend .header__menu;
|
||||
justify-content: flex-end;
|
||||
width: 10rem;
|
||||
min-width: 10rem;
|
||||
|
||||
@media (max-width: $breakpoint-small) {
|
||||
max-width: 4rem;
|
||||
width: unset;
|
||||
min-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,6 +158,7 @@
|
|||
|
||||
.header__navigationItem--profilePic {
|
||||
margin-right: var(--spacing-s);
|
||||
background-color: var(--color-header-button);
|
||||
|
||||
.channel-thumbnail {
|
||||
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 {
|
||||
@extend .header__navigationItem;
|
||||
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 {
|
||||
@extend .header__navigationItem;
|
||||
height: 4rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: var(--spacing-m);
|
||||
margin-right: var(--spacing-m);
|
||||
color: var(--color-text);
|
||||
|
||||
// move to lbry theme?
|
||||
.lbry-icon {
|
||||
height: var(--height-button);
|
||||
width: var(--height-button);
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-small) {
|
||||
margin-right: var(--spacing-m);
|
||||
height: 5rem;
|
||||
|
||||
.button__label {
|
||||
display: none;
|
||||
|
|
Loading…
Reference in a new issue