Management: Fix layout in management boost list (#4645)
This commit is contained in:
parent
1997008ba5
commit
86ddd5bf0b
@ -12,17 +12,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.badgeContainer {
|
.badgeContainer {
|
||||||
--min-shift: calc(10% + var(--digits-count, 1) * 0.4ch);
|
|
||||||
--max-shift: calc(85% - var(--digits-count, 1) * 0.4ch);
|
|
||||||
--shift-x: calc(clamp(var(--min-shift), var(--percent), var(--max-shift)) - 50%);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -1.5rem;
|
top: -1.5rem;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
transform: translate(var(--shift-x), -20px);
|
transform: translate(calc(var(--shift-x) * 100% - 50%), -20px);
|
||||||
|
|
||||||
transition: transform 0.2s ease-in-out;
|
transition: transform 0.2s ease-in-out;
|
||||||
animation: slide-in 0.5s ease-in-out;
|
animation: slide-in 0.5s ease-in-out;
|
||||||
}
|
}
|
||||||
@ -33,7 +29,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
transform: translate(var(--shift-x), -20px);
|
transform: translate(calc(var(--shift-x) * 100% - 50%), -20px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +71,7 @@
|
|||||||
.floating-badge-triangle {
|
.floating-badge-triangle {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -5px;
|
bottom: -4px;
|
||||||
left: calc(var(--tail-position, 0.5) * 100%);
|
left: calc(var(--tail-position, 0.5) * 100%);
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import React, { memo } from '../../lib/teact/teact';
|
import React, {
|
||||||
|
memo, useEffect, useRef, useState,
|
||||||
|
} from '../../lib/teact/teact';
|
||||||
|
|
||||||
import type { IconName } from '../../types/icons';
|
import type { IconName } from '../../types/icons';
|
||||||
|
|
||||||
@ -7,6 +9,7 @@ import buildClassName from '../../util/buildClassName';
|
|||||||
import buildStyle from '../../util/buildStyle';
|
import buildStyle from '../../util/buildStyle';
|
||||||
|
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
|
import useResizeObserver from '../../hooks/useResizeObserver';
|
||||||
|
|
||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
|
|
||||||
@ -21,8 +24,6 @@ type OwnProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PROGRESS_LOCK = 0.1;
|
|
||||||
|
|
||||||
const LimitPreview: FC<OwnProps> = ({
|
const LimitPreview: FC<OwnProps> = ({
|
||||||
leftText,
|
leftText,
|
||||||
rightText,
|
rightText,
|
||||||
@ -32,15 +33,48 @@ const LimitPreview: FC<OwnProps> = ({
|
|||||||
className,
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
// eslint-disable-next-line no-null/no-null
|
||||||
|
const floatingBadgeRef = useRef<HTMLDivElement>(null);
|
||||||
|
// eslint-disable-next-line no-null/no-null
|
||||||
|
const parentContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const [shiftX, setShiftX] = useState(0);
|
||||||
|
const [tailPosition, setTailPosition] = useState(0);
|
||||||
|
|
||||||
|
const updateBadgePosition = () => {
|
||||||
|
if (floatingBadgeRef.current && parentContainerRef.current && progress !== undefined) {
|
||||||
|
const badgeWidth = floatingBadgeRef.current.offsetWidth;
|
||||||
|
const parentWidth = parentContainerRef.current.offsetWidth;
|
||||||
|
const minShift = badgeWidth / 2;
|
||||||
|
const maxShift = parentWidth - badgeWidth / 2;
|
||||||
|
const currentShift = progress * parentWidth;
|
||||||
|
const safeShift = Math.max(minShift, Math.min(currentShift, maxShift));
|
||||||
|
|
||||||
|
setShiftX(safeShift / parentWidth);
|
||||||
|
|
||||||
|
let newTailPosition;
|
||||||
|
if (currentShift < minShift) {
|
||||||
|
newTailPosition = (progress * parentWidth) / (minShift * 2);
|
||||||
|
} else if (currentShift > maxShift) {
|
||||||
|
const progressMapped = (progress - (maxShift / parentWidth)) / (1 - maxShift / parentWidth);
|
||||||
|
newTailPosition = 0.5 + (progressMapped * 0.4);
|
||||||
|
} else {
|
||||||
|
newTailPosition = 0.5;
|
||||||
|
}
|
||||||
|
setTailPosition(newTailPosition);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(updateBadgePosition, [progress]);
|
||||||
|
|
||||||
|
useResizeObserver(parentContainerRef, updateBadgePosition);
|
||||||
|
|
||||||
const hasFloatingBadge = Boolean(floatingBadgeIcon || floatingBadgeText);
|
const hasFloatingBadge = Boolean(floatingBadgeIcon || floatingBadgeText);
|
||||||
const isProgressFull = Boolean(progress) && progress > 0.99;
|
const isProgressFull = Boolean(progress) && progress > 0.99;
|
||||||
const digitsCount = floatingBadgeText?.length;
|
|
||||||
|
|
||||||
const tailPosition = progress && (progress < PROGRESS_LOCK ? 0 : progress > 1 - PROGRESS_LOCK ? 1 : 0.5);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={parentContainerRef}
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
styles.root,
|
styles.root,
|
||||||
hasFloatingBadge && styles.withBadge,
|
hasFloatingBadge && styles.withBadge,
|
||||||
@ -49,13 +83,13 @@ const LimitPreview: FC<OwnProps> = ({
|
|||||||
style={buildStyle(
|
style={buildStyle(
|
||||||
progress !== undefined && `--progress: ${progress}`,
|
progress !== undefined && `--progress: ${progress}`,
|
||||||
tailPosition !== undefined && `--tail-position: ${tailPosition}`,
|
tailPosition !== undefined && `--tail-position: ${tailPosition}`,
|
||||||
digitsCount !== undefined && `--digits-count: ${digitsCount}`,
|
`--shift-x: ${shiftX}`,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{hasFloatingBadge && (
|
{hasFloatingBadge && (
|
||||||
<div className={styles.badgeContainer}>
|
<div className={styles.badgeContainer}>
|
||||||
<div className={styles.floatingBadgeWrapper}>
|
<div className={styles.floatingBadgeWrapper}>
|
||||||
<div className={styles.floatingBadge}>
|
<div className={styles.floatingBadge} ref={floatingBadgeRef}>
|
||||||
{floatingBadgeIcon && <Icon name={floatingBadgeIcon} className={styles.floatingBadgeIcon} />}
|
{floatingBadgeIcon && <Icon name={floatingBadgeIcon} className={styles.floatingBadgeIcon} />}
|
||||||
{floatingBadgeText && (
|
{floatingBadgeText && (
|
||||||
<div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}>
|
<div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
.status {
|
.status {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 0.5rem;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@ -111,3 +111,8 @@
|
|||||||
.giveawayButton {
|
.giveawayButton {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.giveawayIcon {
|
||||||
|
width: 2.75rem;
|
||||||
|
height: 2.75rem;
|
||||||
|
}
|
||||||
|
|||||||
@ -177,7 +177,7 @@ const BoostStatistics = ({
|
|||||||
>
|
>
|
||||||
<Icon name="gift" className={styles.floatingBadgeIcon} />
|
<Icon name="gift" className={styles.floatingBadgeIcon} />
|
||||||
<div className={styles.floatingBadgeValue}>{lang(boost.isFromGiveaway
|
<div className={styles.floatingBadgeValue}>{lang(boost.isFromGiveaway
|
||||||
? 'lng_prizes_results_link' : 'BoostingGift')}
|
? 'BoostingGiveaway' : 'BoostingGift')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -218,11 +218,13 @@ const BoostStatistics = ({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleGiveawayClick = useLastCallback(() => {
|
const handleGiveawayClick = useLastCallback((e) => {
|
||||||
|
e.preventDefault();
|
||||||
openGiveawayModal({ chatId });
|
openGiveawayModal({ chatId });
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleLoadMore = useLastCallback(() => {
|
const handleLoadMore = useLastCallback((e) => {
|
||||||
|
e.preventDefault();
|
||||||
loadMoreBoosters({ isGifts: tabType === 'giftedBoostList' });
|
loadMoreBoosters({ isGifts: tabType === 'giftedBoostList' });
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -243,7 +245,7 @@ const BoostStatistics = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.content}>
|
<div className={styles.section}>
|
||||||
{listToRender?.map((boost) => renderBoostList(boost))}
|
{listToRender?.map((boost) => renderBoostList(boost))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -278,7 +280,11 @@ const BoostStatistics = ({
|
|||||||
>
|
>
|
||||||
<div className={buildClassName(styles.status, 'status-clickable')}>
|
<div className={buildClassName(styles.status, 'status-clickable')}>
|
||||||
<div>
|
<div>
|
||||||
<img src={GIVEAWAY_IMG_LIST[prepaidGiveaway.months]} alt="Giveaway" />
|
<img
|
||||||
|
src={GIVEAWAY_IMG_LIST[prepaidGiveaway.months]}
|
||||||
|
className={styles.giveawayIcon}
|
||||||
|
alt={lang('Giveaway')}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
<h3>
|
<h3>
|
||||||
@ -303,13 +309,12 @@ const BoostStatistics = ({
|
|||||||
<p className="text-muted hint" key="links-hint">{lang('BoostingSelectPaidGiveaway')}</p>
|
<p className="text-muted hint" key="links-hint">{lang('BoostingSelectPaidGiveaway')}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={styles.section}>
|
<div>
|
||||||
{shouldDisplayGiftList ? (
|
{shouldDisplayGiftList ? (
|
||||||
<div
|
<div
|
||||||
className={styles.boostSection}
|
className={buildClassName(styles.boostSection, styles.content)}
|
||||||
>
|
>
|
||||||
<Transition
|
<Transition
|
||||||
key={activeKey}
|
|
||||||
ref={transitionRef}
|
ref={transitionRef}
|
||||||
name={lang.isRtl ? 'slideOptimizedRtl' : 'slideOptimized'}
|
name={lang.isRtl ? 'slideOptimizedRtl' : 'slideOptimized'}
|
||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
@ -322,7 +327,7 @@ const BoostStatistics = ({
|
|||||||
<TabList big activeTab={renderingActiveTab} tabs={tabs} onSwitchTab={setActiveTab} />
|
<TabList big activeTab={renderingActiveTab} tabs={tabs} onSwitchTab={setActiveTab} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<div className={styles.section}>
|
||||||
<h4 className={styles.sectionHeader} dir={lang.isRtl ? 'rtl' : undefined}>
|
<h4 className={styles.sectionHeader} dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
{lang('BoostingBoostsCount', boostStatistics?.boosts?.count)}
|
{lang('BoostingBoostsCount', boostStatistics?.boosts?.count)}
|
||||||
</h4>
|
</h4>
|
||||||
@ -331,28 +336,35 @@ const BoostStatistics = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{boostStatistics?.boosts?.list?.map((boost) => renderBoostList(boost))}
|
{boostStatistics?.boosts?.list?.map((boost) => renderBoostList(boost))}
|
||||||
</>
|
</div>
|
||||||
)}
|
|
||||||
{Boolean(boostersToLoadCount) && (
|
|
||||||
<ListItem
|
|
||||||
key="load-more"
|
|
||||||
className={styles.showMore}
|
|
||||||
disabled={boostStatistics?.isLoadingBoosters}
|
|
||||||
onClick={handleLoadMore}
|
|
||||||
>
|
|
||||||
{boostStatistics?.isLoadingBoosters ? (
|
|
||||||
<Spinner className={styles.loadMoreSpinner} />
|
|
||||||
) : (
|
|
||||||
<Icon name="down" className={styles.down} />
|
|
||||||
)}
|
|
||||||
{lang('ShowVotes', boostersToLoadCount, 'i')}
|
|
||||||
</ListItem>
|
|
||||||
)}
|
)}
|
||||||
|
<div className={styles.section}>
|
||||||
|
{Boolean(boostersToLoadCount) && (
|
||||||
|
<ListItem
|
||||||
|
key="load-more"
|
||||||
|
className={styles.showMore}
|
||||||
|
disabled={boostStatistics?.isLoadingBoosters}
|
||||||
|
onClick={handleLoadMore}
|
||||||
|
>
|
||||||
|
{boostStatistics?.isLoadingBoosters ? (
|
||||||
|
<Spinner className={styles.loadMoreSpinner} />
|
||||||
|
) : (
|
||||||
|
<Icon name="down" className={styles.down} />
|
||||||
|
)}
|
||||||
|
{lang('ShowVotes', boostersToLoadCount, 'i')}
|
||||||
|
</ListItem>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<LinkField className={styles.section} link={status!.boostUrl} withShare title={lang('LinkForBoosting')} />
|
<LinkField className={styles.section} link={status!.boostUrl} withShare title={lang('LinkForBoosting')} />
|
||||||
{isGiveawayAvailable && (
|
{isGiveawayAvailable && (
|
||||||
<div className={styles.section}>
|
<div className={styles.section}>
|
||||||
<ListItem icon="gift" ripple onClick={handleGiveawayClick} className={styles.giveawayButton}>
|
<ListItem
|
||||||
|
key="load-more"
|
||||||
|
icon="gift"
|
||||||
|
onClick={handleGiveawayClick}
|
||||||
|
className={styles.giveawayButton}
|
||||||
|
>
|
||||||
{lang('BoostingGetBoostsViaGifts')}
|
{lang('BoostingGetBoostsViaGifts')}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<p className="text-muted hint" key="links-hint">{lang(
|
<p className="text-muted hint" key="links-hint">{lang(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user