Profile: Optimize accordion transitions (#6488)
This commit is contained in:
parent
6054536ee9
commit
9738c34242
@ -1,5 +1,9 @@
|
||||
@use '../../../styles/mixins';
|
||||
|
||||
.root {
|
||||
cursor: pointer;
|
||||
|
||||
@include mixins.with-vt-type('profileBusinessHours');
|
||||
}
|
||||
|
||||
.top {
|
||||
@ -32,6 +36,8 @@
|
||||
margin-inline-end: 0.375rem;
|
||||
font-size: 1.25rem;
|
||||
color: var(--color-text-secondary);
|
||||
|
||||
@include mixins.with-vt-type('profileBusinessHours');
|
||||
}
|
||||
|
||||
.offset-trigger {
|
||||
@ -54,13 +60,13 @@
|
||||
&:hover {
|
||||
background-color: var(--color-primary-opacity);
|
||||
}
|
||||
|
||||
@include mixins.with-vt-type('profileBusinessHours');
|
||||
}
|
||||
|
||||
.transition {
|
||||
height: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
/* stylelint-disable-next-line plugin/no-low-performance-animation-properties */
|
||||
transition: height 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
|
||||
.timetable {
|
||||
@ -91,3 +97,42 @@
|
||||
.current-day {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
@include mixins.on-active-vt('profileBusinessHours') {
|
||||
&::view-transition-image-pair(.businessHours) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&::view-transition-old(.businessHours),
|
||||
&::view-transition-new(.businessHours) {
|
||||
animation-name: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include mixins.on-active-vt('profileBusinessHoursExpand') {
|
||||
&::view-transition-old(.expandArrow) {
|
||||
animation-name: vt-expand-icon-spin;
|
||||
}
|
||||
|
||||
&::view-transition-new(.expandArrow) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::view-transition-old(.businessHours) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include mixins.on-active-vt('profileBusinessHoursCollapse') {
|
||||
&::view-transition-old(.expandArrow) {
|
||||
animation-name: vt-collapse-icon-spin;
|
||||
}
|
||||
|
||||
&::view-transition-new(.expandArrow) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::view-transition-new(.businessHours) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
import type React from '../../../lib/teact/teact';
|
||||
import {
|
||||
memo, useEffect, useMemo, useRef,
|
||||
memo, useMemo,
|
||||
} from '../../../lib/teact/teact';
|
||||
|
||||
import type { ApiBusinessWorkHours } from '../../../api/types';
|
||||
|
||||
import { requestMeasure, requestMutation } from '../../../lib/fasterdom/fasterdom';
|
||||
import {
|
||||
VTT_PROFILE_BUSINESS_HOURS,
|
||||
VTT_PROFILE_BUSINESS_HOURS_COLLAPSE,
|
||||
VTT_PROFILE_BUSINESS_HOURS_EXPAND,
|
||||
} from '../../../util/animations/viewTransitionTypes';
|
||||
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { formatTime, formatWeekday } from '../../../util/dates/dateFormat';
|
||||
@ -13,6 +16,8 @@ import {
|
||||
getUtcOffset, getWeekStart, shiftTimeRanges, splitDays,
|
||||
} from '../../../util/dates/workHours';
|
||||
|
||||
import { useViewTransition } from '../../../hooks/animations/useViewTransition';
|
||||
import { useVtn } from '../../../hooks/animations/useVtn';
|
||||
import useSelectorSignal from '../../../hooks/data/useSelectorSignal';
|
||||
import useInterval from '../../../hooks/schedulers/useInterval';
|
||||
import useDerivedState from '../../../hooks/useDerivedState';
|
||||
@ -22,7 +27,6 @@ import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
|
||||
import ListItem from '../../ui/ListItem';
|
||||
import Transition, { ACTIVE_SLIDE_CLASS_NAME, TO_SLIDE_CLASS_NAME } from '../../ui/Transition';
|
||||
import Icon from '../icons/Icon';
|
||||
|
||||
import styles from './BusinessHours.module.scss';
|
||||
@ -31,17 +35,21 @@ const DAYS = Array.from({ length: 7 }, (_, i) => i);
|
||||
|
||||
type OwnProps = {
|
||||
businessHours: ApiBusinessWorkHours;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const BusinessHours = ({
|
||||
businessHours,
|
||||
className,
|
||||
}: OwnProps) => {
|
||||
const transitionRef = useRef<HTMLDivElement>();
|
||||
const [isExpanded, expand, collapse] = useFlag(false);
|
||||
const [isMyTime, showInMyTime, showInLocalTime] = useFlag(false);
|
||||
const lang = useOldLang();
|
||||
const oldLang = useOldLang();
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
const { startViewTransition } = useViewTransition();
|
||||
const { createVtnStyle } = useVtn();
|
||||
|
||||
useInterval(forceUpdate, 60 * 1000);
|
||||
|
||||
const timezoneSignal = useSelectorSignal((global) => global.timezones?.byId);
|
||||
@ -62,20 +70,20 @@ const BusinessHours = ({
|
||||
DAYS.forEach((day) => {
|
||||
const segments = days[day];
|
||||
if (!segments) {
|
||||
result[day] = [lang('BusinessHoursDayClosed')];
|
||||
result[day] = [oldLang('BusinessHoursDayClosed')];
|
||||
return;
|
||||
}
|
||||
|
||||
result[day] = segments.map(({ startMinute, endMinute }) => {
|
||||
if (endMinute - startMinute === 24 * 60) return lang('BusinessHoursDayFullOpened');
|
||||
const start = formatTime(lang, weekStart + startMinute * 60 * 1000);
|
||||
const end = formatTime(lang, weekStart + endMinute * 60 * 1000);
|
||||
if (endMinute - startMinute === 24 * 60) return oldLang('BusinessHoursDayFullOpened');
|
||||
const start = formatTime(oldLang, weekStart + startMinute * 60 * 1000);
|
||||
const end = formatTime(oldLang, weekStart + endMinute * 60 * 1000);
|
||||
return `${start} – ${end}`;
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}, [businessHours.workHours, isMyTime, lang, timezoneMinuteDifference]);
|
||||
}, [businessHours.workHours, isMyTime, oldLang, timezoneMinuteDifference]);
|
||||
|
||||
const isBusinessOpen = useMemo(() => {
|
||||
const localTimeHours = shiftTimeRanges(businessHours.workHours, timezoneMinuteDifference);
|
||||
@ -96,41 +104,25 @@ const BusinessHours = ({
|
||||
|
||||
const handleClick = useLastCallback(() => {
|
||||
if (isExpanded) {
|
||||
collapse();
|
||||
startViewTransition(VTT_PROFILE_BUSINESS_HOURS_COLLAPSE, () => {
|
||||
collapse();
|
||||
});
|
||||
} else {
|
||||
expand();
|
||||
startViewTransition(VTT_PROFILE_BUSINESS_HOURS_EXPAND, () => {
|
||||
expand();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const handleTriggerOffset = useLastCallback((e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (isMyTime) {
|
||||
showInLocalTime();
|
||||
} else {
|
||||
showInMyTime();
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!isExpanded) return;
|
||||
const slide = document.querySelector<HTMLElement>(`.${ACTIVE_SLIDE_CLASS_NAME} > .${styles.timetable}`);
|
||||
if (!slide) return;
|
||||
|
||||
const height = slide.offsetHeight;
|
||||
requestMutation(() => {
|
||||
transitionRef.current!.style.height = `${height}px`;
|
||||
});
|
||||
}, [isExpanded]);
|
||||
|
||||
const handleAnimationStart = useLastCallback(() => {
|
||||
const slide = document.querySelector<HTMLElement>(`.${TO_SLIDE_CLASS_NAME} > .${styles.timetable}`)!;
|
||||
|
||||
requestMeasure(() => {
|
||||
const height = slide.offsetHeight;
|
||||
requestMutation(() => {
|
||||
transitionRef.current!.style.height = `${height}px`;
|
||||
});
|
||||
startViewTransition(VTT_PROFILE_BUSINESS_HOURS, () => {
|
||||
if (isMyTime) {
|
||||
showInLocalTime();
|
||||
} else {
|
||||
showInMyTime();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -139,7 +131,8 @@ const BusinessHours = ({
|
||||
icon="clock"
|
||||
iconClassName={styles.icon}
|
||||
multiline
|
||||
className={styles.root}
|
||||
className={buildClassName(styles.root, className)}
|
||||
style={createVtnStyle('businessHours', true)}
|
||||
isStatic={isExpanded}
|
||||
ripple
|
||||
narrow
|
||||
@ -148,48 +141,43 @@ const BusinessHours = ({
|
||||
>
|
||||
<div className={styles.top}>
|
||||
<div className={styles.left}>
|
||||
<div>{lang('BusinessHoursProfile')}</div>
|
||||
<div className={buildClassName(styles.status, isBusinessOpen && styles.statusOpen)}>
|
||||
{isBusinessOpen ? lang('BusinessHoursProfileNowOpen') : lang('BusinessHoursProfileNowClosed')}
|
||||
<div>{oldLang('BusinessHoursProfile')}</div>
|
||||
<div
|
||||
className={buildClassName(styles.status, isBusinessOpen && styles.statusOpen)}
|
||||
>
|
||||
{isBusinessOpen ? oldLang('BusinessHoursProfileNowOpen') : oldLang('BusinessHoursProfileNowClosed')}
|
||||
</div>
|
||||
</div>
|
||||
<Icon className={styles.arrow} name={isExpanded ? 'up' : 'down'} />
|
||||
<Icon className={styles.arrow} style={createVtnStyle('expandArrow', true)} name={isExpanded ? 'up' : 'down'} />
|
||||
</div>
|
||||
{isExpanded && (
|
||||
<div className={styles.bottom}>
|
||||
{Boolean(timezoneMinuteDifference) && (
|
||||
<div
|
||||
className={styles.offsetTrigger}
|
||||
style={createVtnStyle('offsetTrigger')}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onMouseDown={!IS_TOUCH_ENV ? handleTriggerOffset : undefined}
|
||||
onClick={IS_TOUCH_ENV ? handleTriggerOffset : undefined}
|
||||
>
|
||||
{lang(isMyTime ? 'BusinessHoursProfileSwitchMy' : 'BusinessHoursProfileSwitchLocal')}
|
||||
{oldLang(isMyTime ? 'BusinessHoursProfileSwitchMy' : 'BusinessHoursProfileSwitchLocal')}
|
||||
</div>
|
||||
)}
|
||||
<Transition
|
||||
className={styles.transition}
|
||||
ref={transitionRef}
|
||||
name="fade"
|
||||
activeKey={Number(isMyTime)}
|
||||
onStart={handleAnimationStart}
|
||||
>
|
||||
<dl className={styles.timetable}>
|
||||
{DAYS.map((day) => (
|
||||
<>
|
||||
<dt className={buildClassName(styles.weekday, day === currentDay && styles.currentDay)}>
|
||||
{formatWeekday(lang, day === 6 ? 0 : day + 1)}
|
||||
</dt>
|
||||
<dd className={styles.schedule}>
|
||||
{workHours[day].map((segment) => (
|
||||
<div>{segment}</div>
|
||||
))}
|
||||
</dd>
|
||||
</>
|
||||
))}
|
||||
</dl>
|
||||
</Transition>
|
||||
<dl className={styles.timetable}>
|
||||
{DAYS.map((day) => (
|
||||
<>
|
||||
<dt className={buildClassName(styles.weekday, day === currentDay && styles.currentDay)}>
|
||||
{formatWeekday(oldLang, day === 6 ? 0 : day + 1)}
|
||||
</dt>
|
||||
<dd className={styles.schedule}>
|
||||
{workHours[day].map((segment) => (
|
||||
<div>{segment}</div>
|
||||
))}
|
||||
</dd>
|
||||
</>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
)}
|
||||
</ListItem>
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
border-radius: 0.25rem;
|
||||
|
||||
object-fit: cover;
|
||||
|
||||
@include mixins.with-vt-type('chatExtra');
|
||||
}
|
||||
|
||||
.personalChannel {
|
||||
@ -18,6 +20,8 @@
|
||||
column-gap: 0.5rem;
|
||||
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
@include mixins.with-vt-type('chatExtra');
|
||||
}
|
||||
|
||||
.personalChannelTitle {
|
||||
@ -31,6 +35,11 @@
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.phone, .description, .link, .miniapp, .notifications, .location, .note, .savedMessages, .botEmojiStatus,
|
||||
.botLocation, .subscribers {
|
||||
@include mixins.with-vt-type('chatExtra');
|
||||
}
|
||||
|
||||
.botVerificationSection,
|
||||
.sectionInfo {
|
||||
font-size: 0.875rem;
|
||||
@ -39,6 +48,8 @@
|
||||
|
||||
.botVerificationSection {
|
||||
padding-inline: 1.25rem;
|
||||
|
||||
@include mixins.with-vt-type('chatExtra');
|
||||
}
|
||||
|
||||
.botVerificationIcon {
|
||||
@ -71,9 +82,15 @@
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.note {
|
||||
@include mixins.with-vt-type('profileNote');
|
||||
}
|
||||
|
||||
.noteSubtitle {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
|
||||
@include mixins.with-vt-type('profileNote');
|
||||
}
|
||||
|
||||
.noteListItemIcon {
|
||||
@ -87,13 +104,9 @@
|
||||
|
||||
.noteText {
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
|
||||
width: 100%;
|
||||
/* stylelint-disable-next-line plugin/no-low-performance-animation-properties */
|
||||
transition: max-height 0.3s ease;
|
||||
|
||||
&::after {
|
||||
pointer-events: none;
|
||||
@ -111,23 +124,61 @@
|
||||
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
@include mixins.with-vt-type('profileNote');
|
||||
}
|
||||
|
||||
.noteTextCollapsed::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.noteCollapseIcon {
|
||||
.noteExpandIcon {
|
||||
margin-inline-start: 0.125rem;
|
||||
font-size: 0.9375rem;
|
||||
line-height: 0.9375rem;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.expandedIcon {
|
||||
transform: rotate(-180deg);
|
||||
@include mixins.with-vt-type('profileNote');
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: var(--custom-cursor, pointer);
|
||||
}
|
||||
|
||||
@include mixins.on-active-vt('profileNote') {
|
||||
&::view-transition-image-pair(.noteText) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&::view-transition-old(.noteText),
|
||||
&::view-transition-new(.noteText) {
|
||||
animation-name: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include mixins.on-active-vt('profileNoteExpand') {
|
||||
&::view-transition-old(.noteExpandIcon) {
|
||||
animation-name: vt-expand-icon-spin;
|
||||
}
|
||||
|
||||
&::view-transition-new(.noteExpandIcon) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::view-transition-old(.noteText) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include mixins.on-active-vt('profileNoteCollapse') {
|
||||
&::view-transition-old(.noteExpandIcon) {
|
||||
animation-name: vt-collapse-icon-spin;
|
||||
}
|
||||
|
||||
&::view-transition-new(.noteExpandIcon) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::view-transition-new(.noteText) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ import {
|
||||
selectUser,
|
||||
selectUserFullInfo,
|
||||
} from '../../../global/selectors';
|
||||
import { VTT_PROFILE_NOTE_COLLAPSE, VTT_PROFILE_NOTE_EXPAND } from '../../../util/animations/viewTransitionTypes';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { copyTextToClipboard } from '../../../util/clipboard';
|
||||
import { formatPhoneNumberWithCode } from '../../../util/phoneNumber';
|
||||
@ -48,6 +49,8 @@ import formatUsername from '../helpers/formatUsername';
|
||||
import renderText from '../helpers/renderText';
|
||||
import { renderTextWithEntities } from '../helpers/renderTextWithEntities';
|
||||
|
||||
import { useViewTransition } from '../../../hooks/animations/useViewTransition';
|
||||
import { useVtn } from '../../../hooks/animations/useVtn';
|
||||
import useCollapsibleLines from '../../../hooks/element/useCollapsibleLines';
|
||||
import useEffectWithPrevDeps from '../../../hooks/useEffectWithPrevDeps';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
@ -75,7 +78,6 @@ type OwnProps = {
|
||||
isSavedDialog?: boolean;
|
||||
isInSettings?: boolean;
|
||||
className?: string;
|
||||
style?: string;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
@ -105,7 +107,7 @@ const DEFAULT_MAP_CONFIG = {
|
||||
};
|
||||
|
||||
const BOT_VERIFICATION_ICON_SIZE = 16;
|
||||
const MAX_LINES = 3;
|
||||
const NOTE_MAX_LINES = 3;
|
||||
|
||||
const ChatExtra = ({
|
||||
chatOrUserId,
|
||||
@ -127,7 +129,6 @@ const ChatExtra = ({
|
||||
botAppPermissions,
|
||||
botVerification,
|
||||
className,
|
||||
style,
|
||||
isInSettings,
|
||||
canViewSubscribers,
|
||||
}: OwnProps & StateProps) => {
|
||||
@ -163,6 +164,9 @@ const ChatExtra = ({
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
const { startViewTransition } = useViewTransition();
|
||||
const { createVtnStyle } = useVtn();
|
||||
|
||||
const noteTextRef = useRef<HTMLDivElement>();
|
||||
|
||||
const shouldRenderNote = Boolean(note);
|
||||
@ -173,7 +177,7 @@ const ChatExtra = ({
|
||||
setIsCollapsed: setIsNoteCollapsed,
|
||||
} = useCollapsibleLines(
|
||||
noteTextRef,
|
||||
MAX_LINES,
|
||||
NOTE_MAX_LINES,
|
||||
undefined,
|
||||
!shouldRenderNote,
|
||||
);
|
||||
@ -264,11 +268,16 @@ const ChatExtra = ({
|
||||
const canExpandNote = isNoteCollapsible && isNoteCollapsed;
|
||||
|
||||
const handleExpandNote = useLastCallback(() => {
|
||||
setIsNoteCollapsed(false);
|
||||
startViewTransition(VTT_PROFILE_NOTE_EXPAND, () => {
|
||||
setIsNoteCollapsed(false);
|
||||
});
|
||||
});
|
||||
|
||||
const handleToggleNote = useLastCallback(() => {
|
||||
setIsNoteCollapsed((prev) => !prev);
|
||||
const isCollapsed = isNoteCollapsed;
|
||||
startViewTransition(isCollapsed ? VTT_PROFILE_NOTE_EXPAND : VTT_PROFILE_NOTE_COLLAPSE, () => {
|
||||
setIsNoteCollapsed(() => !isCollapsed);
|
||||
});
|
||||
});
|
||||
|
||||
function copy(text: string, entity: string) {
|
||||
@ -382,9 +391,9 @@ const ChatExtra = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={buildClassName('ChatExtra', className)} style={style}>
|
||||
<div className={buildClassName('ChatExtra', className)} style={createVtnStyle('chatExtra')}>
|
||||
{personalChannel && (
|
||||
<div className={styles.personalChannel}>
|
||||
<div className={styles.personalChannel} style={createVtnStyle('personalChannel')}>
|
||||
<h3 className={styles.personalChannelTitle}>{oldLang('ProfileChannel')}</h3>
|
||||
<span className={styles.personalChannelSubscribers}>
|
||||
{oldLang('Subscribers', personalChannel.membersCount, 'i')}
|
||||
@ -400,8 +409,15 @@ const ChatExtra = ({
|
||||
</div>
|
||||
)}
|
||||
{Boolean(formattedNumber?.length) && (
|
||||
|
||||
<ListItem icon="phone" multiline narrow ripple onClick={handlePhoneClick}>
|
||||
<ListItem
|
||||
icon="phone"
|
||||
className={styles.phone}
|
||||
multiline
|
||||
narrow
|
||||
ripple
|
||||
onClick={handlePhoneClick}
|
||||
style={createVtnStyle('phone')}
|
||||
>
|
||||
<span className="title" dir={lang.isRtl ? 'rtl' : undefined}>{formattedNumber}</span>
|
||||
<span className="subtitle">{oldLang('Phone')}</span>
|
||||
</ListItem>
|
||||
@ -410,10 +426,12 @@ const ChatExtra = ({
|
||||
{description && Boolean(description.length) && (
|
||||
<ListItem
|
||||
icon="info"
|
||||
className={styles.description}
|
||||
multiline
|
||||
narrow
|
||||
isStatic
|
||||
allowSelection
|
||||
style={createVtnStyle('description')}
|
||||
>
|
||||
<span className="title word-break allow-selection" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
{
|
||||
@ -432,10 +450,11 @@ const ChatExtra = ({
|
||||
<ListItem
|
||||
icon="link"
|
||||
multiline
|
||||
className={styles.link}
|
||||
narrow
|
||||
ripple
|
||||
|
||||
onClick={() => copy(link, oldLang('SetUrlPlaceholder'))}
|
||||
style={createVtnStyle('link')}
|
||||
>
|
||||
<div className="title">{link}</div>
|
||||
<span className="subtitle">{oldLang('SetUrlPlaceholder')}</span>
|
||||
@ -447,8 +466,10 @@ const ChatExtra = ({
|
||||
{hasMainMiniApp && (
|
||||
<ListItem
|
||||
multiline
|
||||
className={styles.miniapp}
|
||||
isStatic
|
||||
narrow
|
||||
style={createVtnStyle('miniapp')}
|
||||
>
|
||||
<Button
|
||||
className={styles.openAppButton}
|
||||
@ -462,7 +483,14 @@ const ChatExtra = ({
|
||||
</ListItem>
|
||||
)}
|
||||
{!isOwnProfile && !isInSettings && (
|
||||
<ListItem icon={isMuted ? 'mute' : 'unmute'} narrow ripple onClick={handleToggleNotifications}>
|
||||
<ListItem
|
||||
icon={isMuted ? 'mute' : 'unmute'}
|
||||
className={styles.notifications}
|
||||
narrow
|
||||
ripple
|
||||
onClick={handleToggleNotifications}
|
||||
style={createVtnStyle('notifications')}
|
||||
>
|
||||
<span>{lang('Notifications')}</span>
|
||||
<Switcher
|
||||
id="group-notifications"
|
||||
@ -481,6 +509,8 @@ const ChatExtra = ({
|
||||
ripple
|
||||
multiline
|
||||
narrow
|
||||
className={styles.location}
|
||||
style={createVtnStyle('location')}
|
||||
rightElement={locationRightComponent}
|
||||
onClick={handleClickLocation}
|
||||
>
|
||||
@ -496,6 +526,8 @@ const ChatExtra = ({
|
||||
narrow
|
||||
isStatic
|
||||
allowSelection
|
||||
className={styles.note}
|
||||
style={createVtnStyle('note')}
|
||||
>
|
||||
<div
|
||||
ref={noteTextRef}
|
||||
@ -506,6 +538,7 @@ const ChatExtra = ({
|
||||
styles.noteText,
|
||||
isNoteCollapsed && styles.noteTextCollapsed,
|
||||
)}
|
||||
style={createVtnStyle('noteText', true)}
|
||||
dir={lang.isRtl ? 'rtl' : undefined}
|
||||
onClick={canExpandNote ? handleExpandNote : undefined}
|
||||
>
|
||||
@ -514,31 +547,45 @@ const ChatExtra = ({
|
||||
entities: note.entities,
|
||||
})}
|
||||
</div>
|
||||
<div className={buildClassName('subtitle', styles.noteSubtitle)}>
|
||||
<div className={buildClassName('subtitle', styles.noteSubtitle)} style={createVtnStyle('noteSubtitle')}>
|
||||
<span>{lang('UserNoteTitle')}</span>
|
||||
|
||||
<span className={styles.noteHint}>{lang('UserNoteHint')}</span>
|
||||
{isNoteCollapsible && (
|
||||
<Icon
|
||||
className={buildClassName(
|
||||
styles.noteCollapseIcon,
|
||||
styles.noteExpandIcon,
|
||||
styles.clickable,
|
||||
!isNoteCollapsed && styles.expandedIcon,
|
||||
)}
|
||||
style={createVtnStyle('noteExpandIcon', true)}
|
||||
onClick={handleToggleNote}
|
||||
name="down"
|
||||
name={isNoteCollapsed ? 'down' : 'up'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ListItem>
|
||||
)}
|
||||
{hasSavedMessages && !isOwnProfile && !isInSettings && (
|
||||
<ListItem icon="saved-messages" narrow ripple onClick={handleOpenSavedDialog}>
|
||||
<ListItem
|
||||
icon="saved-messages"
|
||||
className={styles.savedMessages}
|
||||
narrow
|
||||
ripple
|
||||
onClick={handleOpenSavedDialog}
|
||||
style={createVtnStyle('savedMessages')}
|
||||
>
|
||||
<span>{oldLang('SavedMessagesTab')}</span>
|
||||
</ListItem>
|
||||
)}
|
||||
{userFullInfo && 'isBotAccessEmojiGranted' in userFullInfo && (
|
||||
<ListItem icon="user" narrow ripple onClick={manageEmojiStatusChange}>
|
||||
<ListItem
|
||||
icon="user"
|
||||
className={styles.botEmojiStatus}
|
||||
narrow
|
||||
ripple
|
||||
onClick={manageEmojiStatusChange}
|
||||
style={createVtnStyle('botEmojiStatus')}
|
||||
>
|
||||
<span>{oldLang('BotProfilePermissionEmojiStatus')}</span>
|
||||
<Switcher
|
||||
label={oldLang('BotProfilePermissionEmojiStatus')}
|
||||
@ -548,7 +595,14 @@ const ChatExtra = ({
|
||||
</ListItem>
|
||||
)}
|
||||
{botAppPermissions?.geolocation !== undefined && (
|
||||
<ListItem icon="location" narrow ripple onClick={handleLocationPermissionChange}>
|
||||
<ListItem
|
||||
icon="location"
|
||||
className={styles.botLocation}
|
||||
narrow
|
||||
ripple
|
||||
onClick={handleLocationPermissionChange}
|
||||
style={createVtnStyle('botLocation')}
|
||||
>
|
||||
<span>{oldLang('BotProfilePermissionLocation')}</span>
|
||||
<Switcher
|
||||
label={oldLang('BotProfilePermissionLocation')}
|
||||
@ -558,13 +612,21 @@ const ChatExtra = ({
|
||||
</ListItem>
|
||||
)}
|
||||
{canViewSubscribers && (
|
||||
<ListItem icon="group" narrow multiline ripple onClick={handleOpenSubscribers}>
|
||||
<ListItem
|
||||
icon="group"
|
||||
narrow
|
||||
multiline
|
||||
ripple
|
||||
className={styles.subscribers}
|
||||
onClick={handleOpenSubscribers}
|
||||
style={createVtnStyle('subscribers')}
|
||||
>
|
||||
<div className="title">{lang('ProfileItemSubscribers')}</div>
|
||||
<span className="subtitle">{lang.number(chat?.membersCount || 0)}</span>
|
||||
</ListItem>
|
||||
)}
|
||||
{botVerification && (
|
||||
<div className={styles.botVerificationSection}>
|
||||
<div className={styles.botVerificationSection} style={createVtnStyle('botVerification')}>
|
||||
<CustomEmoji
|
||||
className={styles.botVerificationIcon}
|
||||
documentId={botVerification.iconId}
|
||||
|
||||
@ -1116,7 +1116,6 @@ const Profile = ({
|
||||
chatOrUserId={profileId}
|
||||
isSavedDialog={isSavedDialog}
|
||||
isOwnProfile={isOwnProfile}
|
||||
style={createVtnStyle('chatExtra')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -424,6 +424,18 @@ body:not(.is-ios) {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vt-expand-icon-spin {
|
||||
to {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vt-collapse-icon-spin {
|
||||
to {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.component-theme-dark {
|
||||
--color-background: rgb(33, 33, 33);
|
||||
--color-background-compact-menu: rgb(33, 33, 33, 0.867);
|
||||
|
||||
@ -21,3 +21,13 @@ export const VTT_RIGHT_PROFILE_EXPAND = VTT_RIGHT_PROFILE_AVATAR.with('profileEx
|
||||
export const VTT_RIGHT_PROFILE_COLLAPSE = VTT_RIGHT_PROFILE_AVATAR.with('profileCollapse');
|
||||
|
||||
export const VTT_PROFILE_GIFTS = VTT_RIGHT_COLUMN.with('profileGifts');
|
||||
|
||||
export const VTT_CHAT_EXTRA = VTT_RIGHT_COLUMN.with('chatExtra');
|
||||
|
||||
export const VTT_PROFILE_BUSINESS_HOURS = VTT_CHAT_EXTRA.with('profileBusinessHours');
|
||||
export const VTT_PROFILE_BUSINESS_HOURS_EXPAND = VTT_PROFILE_BUSINESS_HOURS.with('profileBusinessHoursExpand');
|
||||
export const VTT_PROFILE_BUSINESS_HOURS_COLLAPSE = VTT_PROFILE_BUSINESS_HOURS.with('profileBusinessHoursCollapse');
|
||||
|
||||
export const VTT_PROFILE_NOTE = VTT_CHAT_EXTRA.with('profileNote');
|
||||
export const VTT_PROFILE_NOTE_EXPAND = VTT_PROFILE_NOTE.with('profileNoteExpand');
|
||||
export const VTT_PROFILE_NOTE_COLLAPSE = VTT_PROFILE_NOTE.with('profileNoteCollapse');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user