Forum Panel: Various optimizations
This commit is contained in:
parent
d65f1d99fc
commit
556c4c0b21
@ -68,7 +68,7 @@ const ArchivedChats: FC<OwnProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
{shouldRenderTitle && <h3 className={titleClassNames}>{lang('ArchivedChats')}</h3>}
|
{shouldRenderTitle && <h3 className={titleClassNames}>{lang('ArchivedChats')}</h3>}
|
||||||
</div>
|
</div>
|
||||||
<ChatList folderType="archived" isActive={isActive} />
|
<ChatList folderType="archived" isActive={isActive} isForumPanelOpen={isForumPanelOpen} />
|
||||||
{shouldRenderForumPanel && (
|
{shouldRenderForumPanel && (
|
||||||
<ForumPanel
|
<ForumPanel
|
||||||
isOpen={isForumPanelOpen}
|
isOpen={isForumPanelOpen}
|
||||||
|
|||||||
52
src/components/left/main/AvatarBadge.tsx
Normal file
52
src/components/left/main/AvatarBadge.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import type { FC } from '../../../lib/teact/teact';
|
||||||
|
import React, { memo } from '../../../lib/teact/teact';
|
||||||
|
import { withGlobal } from '../../../global';
|
||||||
|
|
||||||
|
import type { ApiChat } from '../../../api/types';
|
||||||
|
|
||||||
|
import { selectIsChatMuted } from '../../../global/helpers';
|
||||||
|
import {
|
||||||
|
selectChat,
|
||||||
|
selectNotifySettings,
|
||||||
|
selectNotifyExceptions,
|
||||||
|
selectIsForumPanelOpen,
|
||||||
|
} from '../../../global/selectors';
|
||||||
|
|
||||||
|
import Badge from './Badge';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
chatId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
chat?: ApiChat;
|
||||||
|
isMuted?: boolean;
|
||||||
|
isForumPanelActive?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AvatarBadge: FC<OwnProps & StateProps> = ({
|
||||||
|
chat,
|
||||||
|
isMuted,
|
||||||
|
isForumPanelActive,
|
||||||
|
}) => {
|
||||||
|
return chat && (
|
||||||
|
<div className="avatar-badge-wrapper">
|
||||||
|
<Badge chat={chat} isMuted={isMuted} shouldShowOnlyMostImportant forceHidden={!isForumPanelActive} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>(
|
||||||
|
(global, { chatId }): StateProps => {
|
||||||
|
const chat = selectChat(global, chatId);
|
||||||
|
if (!chat) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
chat,
|
||||||
|
isMuted: selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)),
|
||||||
|
isForumPanelActive: selectIsForumPanelOpen(global),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
)(AvatarBadge));
|
||||||
@ -15,12 +15,17 @@
|
|||||||
|
|
||||||
&.animate-opacity {
|
&.animate-opacity {
|
||||||
will-change: opacity;
|
will-change: opacity;
|
||||||
transition: opacity 250ms ease;
|
transition: opacity 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.animate-transform {
|
&.animate-transform {
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
transition: transform 250ms ease;
|
transition: transform 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.animate-collapse {
|
||||||
|
will-change: transform;
|
||||||
|
transition: transform var(--layer-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
@ -29,7 +34,7 @@
|
|||||||
border-color: var(--color-chat-hover);
|
border-color: var(--color-chat-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-badge-wrapper {
|
.avatar-badge-wrapper {
|
||||||
--outline-color: var(--color-chat-hover);
|
--outline-color: var(--color-chat-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +43,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Super specific selector to override the same in `ListItem`
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
&:not(.has-ripple):not(.is-static),
|
||||||
|
body.animation-level-0 & {
|
||||||
|
.ListItem-button:active {
|
||||||
|
--background-color: var(--color-chat-hover) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:last-of-type {
|
&:last-of-type {
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
@ -55,17 +70,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active-forum {
|
&.selected-forum {
|
||||||
.status-badge-wrapper {
|
.avatar-badge-wrapper {
|
||||||
--outline-color: var(--color-chat-hover);
|
--outline-color: var(--color-chat-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 600px) {
|
@media (min-width: 600px) {
|
||||||
&.active-forum.forum,
|
&.selected-forum.forum,
|
||||||
&.active-forum.forum:hover {
|
&.selected-forum.forum:hover {
|
||||||
.status-badge-wrapper {
|
.avatar-badge-wrapper {
|
||||||
--outline-color: var(--color-chat-hover);
|
--outline-color: var(--color-chat-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,7 +126,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Badge:not(.pinned) {
|
.Badge:not(.pinned) {
|
||||||
background: var(--color-white);
|
|
||||||
color: var(--color-chat-active);
|
color: var(--color-chat-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,35 +134,18 @@
|
|||||||
background: #FFFFFF33;
|
background: #FFFFFF33;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-badge-wrapper-visible .Badge:not(.pinned).muted {
|
.avatar-badge-wrapper .Badge:not(.pinned) {
|
||||||
background: var(--color-chat-active-greyed);
|
|
||||||
--outline-color: transparent;
|
--outline-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-badge-wrapper-visible .Badge:not(.pinned):not(.muted) {
|
.avatar-badge-wrapper .Badge:not(.pinned).muted {
|
||||||
--outline-color: transparent;
|
background: var(--color-gray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.smaller .ListItem-button {
|
&.selected-forum {
|
||||||
height: 4.5rem;
|
--background-color: var(--color-chat-hover) !important;
|
||||||
}
|
|
||||||
|
|
||||||
&.active-forum::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: -0.5rem;
|
|
||||||
width: 0.375rem;
|
|
||||||
height: 75%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
|
|
||||||
background: var(--color-primary);
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
border-start-end-radius: var(--border-radius-default);
|
|
||||||
border-end-end-radius: var(--border-radius-default);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
@ -169,7 +166,7 @@
|
|||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-badge-wrapper {
|
.avatar-badge-wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0.5rem;
|
right: 0.5rem;
|
||||||
@ -182,12 +179,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Badge-transition {
|
.Badge-transition {
|
||||||
transition: opacity 250ms ease, transform 250ms ease; // Same as Forum Panel
|
transition: opacity var(--layer-transition), transform var(--layer-transition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
transition: opacity 250ms ease, transform 250ms ease; // Same as Forum Panel
|
transition: opacity 300ms ease, transform var(--layer-transition);
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
margin-top: -0.125rem;
|
margin-top: -0.125rem;
|
||||||
@ -316,19 +313,5 @@
|
|||||||
unicode-bidi: plaintext;
|
unicode-bidi: plaintext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active-forum::before {
|
|
||||||
left: auto;
|
|
||||||
right: 0.0625rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.smaller .info {
|
|
||||||
transform: translateX(-25%);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[dir="rtl"].smaller .info {
|
|
||||||
transform: translateX(25%);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import type { FC } from '../../../lib/teact/teact';
|
import type { FC } from '../../../lib/teact/teact';
|
||||||
import React, {
|
import React, { memo, useCallback, useEffect } from '../../../lib/teact/teact';
|
||||||
memo, useCallback, useEffect, useLayoutEffect, useRef,
|
|
||||||
} from '../../../lib/teact/teact';
|
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||||
@ -18,7 +16,6 @@ import type {
|
|||||||
import type { AnimationLevel } from '../../../types';
|
import type { AnimationLevel } from '../../../types';
|
||||||
import type { ChatAnimationTypes } from './hooks';
|
import type { ChatAnimationTypes } from './hooks';
|
||||||
|
|
||||||
import { ANIMATION_END_DELAY } from '../../../config';
|
|
||||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
||||||
import {
|
import {
|
||||||
@ -40,40 +37,35 @@ import {
|
|||||||
selectIsDefaultEmojiStatusPack,
|
selectIsDefaultEmojiStatusPack,
|
||||||
selectTopicFromMessage,
|
selectTopicFromMessage,
|
||||||
selectThreadParam,
|
selectThreadParam,
|
||||||
selectIsForumPanelOpen,
|
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { fastRaf } from '../../../util/schedulers';
|
|
||||||
import buildStyle from '../../../util/buildStyle';
|
|
||||||
|
|
||||||
import useChatContextActions from '../../../hooks/useChatContextActions';
|
import useChatContextActions from '../../../hooks/useChatContextActions';
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
import useChatListEntry from './hooks/useChatListEntry';
|
import useChatListEntry from './hooks/useChatListEntry';
|
||||||
import { useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
import { useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||||
import usePrevious from '../../../hooks/usePrevious';
|
|
||||||
|
|
||||||
|
import ListItem from '../../ui/ListItem';
|
||||||
import Avatar from '../../common/Avatar';
|
import Avatar from '../../common/Avatar';
|
||||||
import LastMessageMeta from '../../common/LastMessageMeta';
|
import LastMessageMeta from '../../common/LastMessageMeta';
|
||||||
import DeleteChatModal from '../../common/DeleteChatModal';
|
import DeleteChatModal from '../../common/DeleteChatModal';
|
||||||
import ListItem from '../../ui/ListItem';
|
|
||||||
import Badge from './Badge';
|
|
||||||
import ChatFolderModal from '../ChatFolderModal.async';
|
|
||||||
import ChatCallStatus from './ChatCallStatus';
|
|
||||||
import ReportModal from '../../common/ReportModal';
|
import ReportModal from '../../common/ReportModal';
|
||||||
import FullNameTitle from '../../common/FullNameTitle';
|
import FullNameTitle from '../../common/FullNameTitle';
|
||||||
|
import ChatFolderModal from '../ChatFolderModal.async';
|
||||||
|
import ChatCallStatus from './ChatCallStatus';
|
||||||
|
import Badge from './Badge';
|
||||||
|
import AvatarBadge from './AvatarBadge';
|
||||||
|
|
||||||
import './Chat.scss';
|
import './Chat.scss';
|
||||||
|
|
||||||
const TRANSFORM_TO_TOPIC_LIST_ANIMATION_DELAY = 300;
|
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
folderId?: number;
|
folderId?: number;
|
||||||
orderDiff: number;
|
orderDiff: number;
|
||||||
animationType: ChatAnimationTypes;
|
animationType: ChatAnimationTypes;
|
||||||
isPinned?: boolean;
|
isPinned?: boolean;
|
||||||
offsetTopInSmallerMode: number;
|
|
||||||
offsetTop: number;
|
offsetTop: number;
|
||||||
|
offsetCollapseDelta: number;
|
||||||
observeIntersection?: ObserveFn;
|
observeIntersection?: ObserveFn;
|
||||||
onDragEnter?: (chatId: string) => void;
|
onDragEnter?: (chatId: string) => void;
|
||||||
};
|
};
|
||||||
@ -92,13 +84,12 @@ type StateProps = {
|
|||||||
draft?: ApiFormattedText;
|
draft?: ApiFormattedText;
|
||||||
animationLevel?: AnimationLevel;
|
animationLevel?: AnimationLevel;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
isForumPanelActive?: boolean;
|
isSelectedForum?: boolean;
|
||||||
canScrollDown?: boolean;
|
canScrollDown?: boolean;
|
||||||
canChangeFolder?: boolean;
|
canChangeFolder?: boolean;
|
||||||
lastSyncTime?: number;
|
lastSyncTime?: number;
|
||||||
lastMessageTopic?: ApiTopic;
|
lastMessageTopic?: ApiTopic;
|
||||||
typingStatus?: ApiTypingStatus;
|
typingStatus?: ApiTypingStatus;
|
||||||
forumPanelChatId?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Chat: FC<OwnProps & StateProps> = ({
|
const Chat: FC<OwnProps & StateProps> = ({
|
||||||
@ -118,24 +109,22 @@ const Chat: FC<OwnProps & StateProps> = ({
|
|||||||
lastMessageOutgoingStatus,
|
lastMessageOutgoingStatus,
|
||||||
actionTargetMessage,
|
actionTargetMessage,
|
||||||
actionTargetChatId,
|
actionTargetChatId,
|
||||||
offsetTopInSmallerMode,
|
|
||||||
offsetTop,
|
offsetTop,
|
||||||
|
offsetCollapseDelta,
|
||||||
draft,
|
draft,
|
||||||
animationLevel,
|
animationLevel,
|
||||||
isSelected,
|
isSelected,
|
||||||
isForumPanelActive,
|
isSelectedForum,
|
||||||
canScrollDown,
|
canScrollDown,
|
||||||
canChangeFolder,
|
canChangeFolder,
|
||||||
lastSyncTime,
|
lastSyncTime,
|
||||||
lastMessageTopic,
|
lastMessageTopic,
|
||||||
typingStatus,
|
typingStatus,
|
||||||
forumPanelChatId,
|
|
||||||
onDragEnter,
|
onDragEnter,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
openChat,
|
openChat,
|
||||||
openForumPanel,
|
openForumPanel,
|
||||||
closeForumPanel,
|
|
||||||
focusLastMessage,
|
focusLastMessage,
|
||||||
loadTopics,
|
loadTopics,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
@ -161,27 +150,24 @@ const Chat: FC<OwnProps & StateProps> = ({
|
|||||||
lastMessageTopic,
|
lastMessageTopic,
|
||||||
lastMessageSender,
|
lastMessageSender,
|
||||||
observeIntersection,
|
observeIntersection,
|
||||||
|
|
||||||
animationType,
|
animationType,
|
||||||
animationLevel,
|
animationLevel,
|
||||||
orderDiff,
|
orderDiff,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
if (chat?.isForum) {
|
if (isForum) {
|
||||||
openForumPanel({ chatId });
|
openForumPanel({ chatId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forumPanelChatId) closeForumPanel();
|
|
||||||
openChat({ id: chatId, shouldReplaceHistory: true }, { forceOnHeavyAnimation: true });
|
openChat({ id: chatId, shouldReplaceHistory: true }, { forceOnHeavyAnimation: true });
|
||||||
|
|
||||||
if (isSelected && canScrollDown) {
|
if (isSelected && canScrollDown) {
|
||||||
focusLastMessage();
|
focusLastMessage();
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
chat?.isForum, forumPanelChatId, closeForumPanel, openChat, chatId, isSelected, canScrollDown, openForumPanel,
|
isForum, openChat, chatId, isSelected, canScrollDown, openForumPanel, focusLastMessage,
|
||||||
focusLastMessage,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleDragEnter = useCallback((e) => {
|
const handleDragEnter = useCallback((e) => {
|
||||||
@ -225,31 +211,6 @@ const Chat: FC<OwnProps & StateProps> = ({
|
|||||||
}
|
}
|
||||||
}, [chat, chatId, isForum, isIntersecting, lastSyncTime, loadTopics]);
|
}, [chat, chatId, isForum, isIntersecting, lastSyncTime, loadTopics]);
|
||||||
|
|
||||||
const isOnForumPanel = chatId === forumPanelChatId;
|
|
||||||
const prevIsForumPanelActive = usePrevious(isForumPanelActive);
|
|
||||||
const isAnimatingRef = useRef(false);
|
|
||||||
|
|
||||||
if (prevIsForumPanelActive !== isForumPanelActive) {
|
|
||||||
isAnimatingRef.current = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animate changing to smaller chat size when navigating to/from forum topic list
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
const current = ref.current;
|
|
||||||
|
|
||||||
if (current && isAnimatingRef.current && isForumPanelActive !== prevIsForumPanelActive) {
|
|
||||||
current.classList.add('animate-transform');
|
|
||||||
current.style.transform = '';
|
|
||||||
setTimeout(() => {
|
|
||||||
// Wait one more frame for better animation performance
|
|
||||||
fastRaf(() => {
|
|
||||||
isAnimatingRef.current = false;
|
|
||||||
current.classList.remove('animate-transform');
|
|
||||||
});
|
|
||||||
}, TRANSFORM_TO_TOPIC_LIST_ANIMATION_DELAY + ANIMATION_END_DELAY);
|
|
||||||
}
|
|
||||||
}, [ref, isForumPanelActive, prevIsForumPanelActive]);
|
|
||||||
|
|
||||||
if (!chat) {
|
if (!chat) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -259,23 +220,20 @@ const Chat: FC<OwnProps & StateProps> = ({
|
|||||||
isUserId(chatId) ? 'private' : 'group',
|
isUserId(chatId) ? 'private' : 'group',
|
||||||
isForum && 'forum',
|
isForum && 'forum',
|
||||||
isSelected && 'selected',
|
isSelected && 'selected',
|
||||||
isForumPanelActive && 'smaller',
|
isSelectedForum && 'selected-forum',
|
||||||
isOnForumPanel && 'active-forum',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const chatTop = isForumPanelActive ? (offsetTop - offsetTopInSmallerMode) : offsetTop;
|
|
||||||
const offsetAnimate = isForumPanelActive ? offsetTopInSmallerMode : -offsetTopInSmallerMode;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={className}
|
className={className}
|
||||||
style={buildStyle(`top: ${chatTop}px`, isAnimatingRef.current && `transform: translateY(${offsetAnimate}px)`)}
|
style={`top: ${offsetTop}px`}
|
||||||
ripple={!isForum && !IS_SINGLE_COLUMN_LAYOUT}
|
ripple={!isForum && !IS_SINGLE_COLUMN_LAYOUT}
|
||||||
contextActions={contextActions}
|
contextActions={contextActions}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
onDragEnter={handleDragEnter}
|
onDragEnter={handleDragEnter}
|
||||||
shouldUsePortalForMenu={isForumPanelActive}
|
offsetCollapseDelta={offsetCollapseDelta}
|
||||||
|
withPortalForMenu
|
||||||
>
|
>
|
||||||
<div className="status">
|
<div className="status">
|
||||||
<Avatar
|
<Avatar
|
||||||
@ -288,9 +246,7 @@ const Chat: FC<OwnProps & StateProps> = ({
|
|||||||
withVideo
|
withVideo
|
||||||
observeIntersection={observeIntersection}
|
observeIntersection={observeIntersection}
|
||||||
/>
|
/>
|
||||||
<div className="status-badge-wrapper">
|
<AvatarBadge chatId={chatId} />
|
||||||
<Badge chat={chat} isMuted={isMuted} shouldShowOnlyMostImportant forceHidden={!isForumPanelActive} />
|
|
||||||
</div>
|
|
||||||
{chat.isCallActive && chat.isCallNotEmpty && (
|
{chat.isCallActive && chat.isCallNotEmpty && (
|
||||||
<ChatCallStatus isSelected={isSelected} isActive={animationLevel !== 0} />
|
<ChatCallStatus isSelected={isSelected} isActive={animationLevel !== 0} />
|
||||||
)}
|
)}
|
||||||
@ -368,8 +324,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
threadId: currentThreadId,
|
threadId: currentThreadId,
|
||||||
type: messageListType,
|
type: messageListType,
|
||||||
} = selectCurrentMessageList(global) || {};
|
} = selectCurrentMessageList(global) || {};
|
||||||
const isForumPanelActive = selectIsForumPanelOpen(global);
|
|
||||||
const isSelected = chatId === currentChatId && currentThreadId === MAIN_THREAD_ID;
|
const isSelected = chatId === currentChatId && currentThreadId === MAIN_THREAD_ID;
|
||||||
|
const isSelectedForum = chatId === global.forumPanelChatId;
|
||||||
|
|
||||||
const user = privateChatUserId ? selectUser(global, privateChatUserId) : undefined;
|
const user = privateChatUserId ? selectUser(global, privateChatUserId) : undefined;
|
||||||
const userStatus = privateChatUserId ? selectUserStatus(global, privateChatUserId) : undefined;
|
const userStatus = privateChatUserId ? selectUserStatus(global, privateChatUserId) : undefined;
|
||||||
@ -388,8 +344,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
actionTargetMessage,
|
actionTargetMessage,
|
||||||
draft: selectDraft(global, chatId, MAIN_THREAD_ID),
|
draft: selectDraft(global, chatId, MAIN_THREAD_ID),
|
||||||
animationLevel: global.settings.byKey.animationLevel,
|
animationLevel: global.settings.byKey.animationLevel,
|
||||||
isForumPanelActive,
|
|
||||||
isSelected,
|
isSelected,
|
||||||
|
isSelectedForum,
|
||||||
canScrollDown: isSelected && messageListType === 'thread',
|
canScrollDown: isSelected && messageListType === 'thread',
|
||||||
canChangeFolder: (global.chatFolders.orderedIds?.length || 0) > 1,
|
canChangeFolder: (global.chatFolders.orderedIds?.length || 0) > 1,
|
||||||
lastSyncTime: global.lastSyncTime,
|
lastSyncTime: global.lastSyncTime,
|
||||||
@ -401,7 +357,6 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
isEmojiStatusColored,
|
isEmojiStatusColored,
|
||||||
lastMessageTopic,
|
lastMessageTopic,
|
||||||
typingStatus,
|
typingStatus,
|
||||||
forumPanelChatId: global.forumPanelChatId,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(Chat));
|
)(Chat));
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { useFolderManagerForUnreadCounters } from '../../../hooks/useFolderManag
|
|||||||
import Transition from '../../ui/Transition';
|
import Transition from '../../ui/Transition';
|
||||||
import TabList from '../../ui/TabList';
|
import TabList from '../../ui/TabList';
|
||||||
import ChatList from './ChatList';
|
import ChatList from './ChatList';
|
||||||
|
import { selectIsForumPanelOpen } from '../../../global/selectors';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
onScreenSelect: (screen: SettingsScreens) => void;
|
onScreenSelect: (screen: SettingsScreens) => void;
|
||||||
@ -34,6 +35,7 @@ type StateProps = {
|
|||||||
orderedFolderIds?: number[];
|
orderedFolderIds?: number[];
|
||||||
activeChatFolder: number;
|
activeChatFolder: number;
|
||||||
currentUserId?: string;
|
currentUserId?: string;
|
||||||
|
isForumPanelOpen?: boolean;
|
||||||
lastSyncTime?: number;
|
lastSyncTime?: number;
|
||||||
shouldSkipHistoryAnimations?: boolean;
|
shouldSkipHistoryAnimations?: boolean;
|
||||||
maxFolders: number;
|
maxFolders: number;
|
||||||
@ -49,6 +51,7 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
|
|||||||
orderedFolderIds,
|
orderedFolderIds,
|
||||||
activeChatFolder,
|
activeChatFolder,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
|
isForumPanelOpen,
|
||||||
lastSyncTime,
|
lastSyncTime,
|
||||||
shouldSkipHistoryAnimations,
|
shouldSkipHistoryAnimations,
|
||||||
maxFolders,
|
maxFolders,
|
||||||
@ -195,27 +198,17 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
|
|||||||
function renderCurrentTab(isActive: boolean) {
|
function renderCurrentTab(isActive: boolean) {
|
||||||
const activeFolder = Object.values(chatFoldersById)
|
const activeFolder = Object.values(chatFoldersById)
|
||||||
.find(({ id }) => id === folderTabs![activeChatFolder].id);
|
.find(({ id }) => id === folderTabs![activeChatFolder].id);
|
||||||
|
const isFolder = activeFolder && !isInAllChatsFolder;
|
||||||
if (!activeFolder || isInAllChatsFolder) {
|
|
||||||
return (
|
|
||||||
<ChatList
|
|
||||||
folderType="all"
|
|
||||||
isActive={isActive}
|
|
||||||
lastSyncTime={lastSyncTime}
|
|
||||||
foldersDispatch={foldersDispatch}
|
|
||||||
onScreenSelect={onScreenSelect}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChatList
|
<ChatList
|
||||||
folderType="folder"
|
folderType={isFolder ? 'folder' : 'all'}
|
||||||
folderId={activeFolder.id}
|
folderId={isFolder ? activeFolder.id : undefined}
|
||||||
isActive={isActive}
|
isActive={isActive}
|
||||||
|
isForumPanelOpen={isForumPanelOpen}
|
||||||
lastSyncTime={lastSyncTime}
|
lastSyncTime={lastSyncTime}
|
||||||
onScreenSelect={onScreenSelect}
|
|
||||||
foldersDispatch={foldersDispatch}
|
foldersDispatch={foldersDispatch}
|
||||||
|
onScreenSelect={onScreenSelect}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -259,16 +252,15 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
shouldSkipHistoryAnimations,
|
shouldSkipHistoryAnimations,
|
||||||
} = global;
|
} = global;
|
||||||
|
|
||||||
const maxFolders = selectCurrentLimit(global, 'dialogFilters');
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chatFoldersById,
|
chatFoldersById,
|
||||||
orderedFolderIds,
|
orderedFolderIds,
|
||||||
activeChatFolder,
|
activeChatFolder,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
|
isForumPanelOpen: selectIsForumPanelOpen(global),
|
||||||
lastSyncTime,
|
lastSyncTime,
|
||||||
shouldSkipHistoryAnimations,
|
shouldSkipHistoryAnimations,
|
||||||
maxFolders,
|
maxFolders: selectCurrentLimit(global, 'dialogFilters'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(ChatFolders));
|
)(ChatFolders));
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
import { IS_MAC_OS, IS_PWA } from '../../../util/environment';
|
import { IS_MAC_OS, IS_PWA } from '../../../util/environment';
|
||||||
import { getPinnedChatsCount, getOrderKey } from '../../../util/folderManager';
|
import { getPinnedChatsCount, getOrderKey } from '../../../util/folderManager';
|
||||||
import { selectChat } from '../../../global/selectors';
|
import { selectChat } from '../../../global/selectors';
|
||||||
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
|
||||||
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
|
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
|
||||||
import { useFolderManagerForOrderedIds } from '../../../hooks/useFolderManager';
|
import { useFolderManagerForOrderedIds } from '../../../hooks/useFolderManager';
|
||||||
@ -28,11 +29,13 @@ import InfiniteScroll from '../../ui/InfiniteScroll';
|
|||||||
import Loading from '../../ui/Loading';
|
import Loading from '../../ui/Loading';
|
||||||
import Chat from './Chat';
|
import Chat from './Chat';
|
||||||
import EmptyFolder from './EmptyFolder';
|
import EmptyFolder from './EmptyFolder';
|
||||||
|
import useCollapseWithForumPanel from './hooks/useCollapseWithForumPanel';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
folderType: 'all' | 'archived' | 'folder';
|
folderType: 'all' | 'archived' | 'folder';
|
||||||
folderId?: number;
|
folderId?: number;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
isForumPanelOpen?: boolean;
|
||||||
lastSyncTime?: number;
|
lastSyncTime?: number;
|
||||||
foldersDispatch?: FolderEditDispatch;
|
foldersDispatch?: FolderEditDispatch;
|
||||||
onScreenSelect?: (screen: SettingsScreens) => void;
|
onScreenSelect?: (screen: SettingsScreens) => void;
|
||||||
@ -45,6 +48,7 @@ const ChatList: FC<OwnProps> = ({
|
|||||||
folderType,
|
folderType,
|
||||||
folderId,
|
folderId,
|
||||||
isActive,
|
isActive,
|
||||||
|
isForumPanelOpen,
|
||||||
foldersDispatch,
|
foldersDispatch,
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
}) => {
|
}) => {
|
||||||
@ -105,6 +109,8 @@ const ChatList: FC<OwnProps> = ({
|
|||||||
throttleMs: INTERSECTION_THROTTLE,
|
throttleMs: INTERSECTION_THROTTLE,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useCollapseWithForumPanel(containerRef, isForumPanelOpen);
|
||||||
|
|
||||||
const handleDragEnter = useDebouncedCallback((chatId: string) => {
|
const handleDragEnter = useDebouncedCallback((chatId: string) => {
|
||||||
if (shouldIgnoreDragRef.current) {
|
if (shouldIgnoreDragRef.current) {
|
||||||
shouldIgnoreDragRef.current = false;
|
shouldIgnoreDragRef.current = false;
|
||||||
@ -143,8 +149,9 @@ const ChatList: FC<OwnProps> = ({
|
|||||||
|
|
||||||
return viewportIds!.map((id, i) => {
|
return viewportIds!.map((id, i) => {
|
||||||
const isPinned = viewportOffset + i < pinnedCount;
|
const isPinned = viewportOffset + i < pinnedCount;
|
||||||
const chatTop = currentChatListHeight;
|
const expendedOffsetTop = currentChatListHeight;
|
||||||
const chatTopSmaller = (viewportOffset + i) * CHAT_HEIGHT_PX;
|
const collapsedOffsetTop = (viewportOffset + i) * CHAT_HEIGHT_PX;
|
||||||
|
|
||||||
currentChatListHeight += (selectChat(global, id)!.isForum ? CHAT_HEIGHT_FORUM_PX : CHAT_HEIGHT_PX);
|
currentChatListHeight += (selectChat(global, id)!.isForum ? CHAT_HEIGHT_FORUM_PX : CHAT_HEIGHT_PX);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -156,8 +163,8 @@ const ChatList: FC<OwnProps> = ({
|
|||||||
folderId={folderId}
|
folderId={folderId}
|
||||||
animationType={getAnimationType(id)}
|
animationType={getAnimationType(id)}
|
||||||
orderDiff={orderDiffById[id]}
|
orderDiff={orderDiffById[id]}
|
||||||
offsetTop={chatTop}
|
offsetTop={isForumPanelOpen ? collapsedOffsetTop : expendedOffsetTop}
|
||||||
offsetTopInSmallerMode={chatTop - chatTopSmaller}
|
offsetCollapseDelta={expendedOffsetTop - collapsedOffsetTop}
|
||||||
observeIntersection={observe}
|
observeIntersection={observe}
|
||||||
onDragEnter={handleDragEnter}
|
onDragEnter={handleDragEnter}
|
||||||
/>
|
/>
|
||||||
@ -167,7 +174,7 @@ const ChatList: FC<OwnProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
className="chat-list custom-scroll"
|
className={buildClassName('chat-list custom-scroll', isForumPanelOpen && 'forum-panel-open')}
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
items={viewportIds}
|
items={viewportIds}
|
||||||
preloadBackwards={CHAT_LIST_SLICE}
|
preloadBackwards={CHAT_LIST_SLICE}
|
||||||
|
|||||||
@ -10,6 +10,10 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
left: 4.3125rem;
|
||||||
|
}
|
||||||
|
|
||||||
&.rtl {
|
&.rtl {
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 4.75rem;
|
right: 4.75rem;
|
||||||
@ -18,7 +22,7 @@
|
|||||||
border-right: 1px solid var(--color-borders);
|
border-right: 1px solid var(--color-borders);
|
||||||
}
|
}
|
||||||
|
|
||||||
transition: transform 250ms ease; // Same as `.Chat > .info`
|
transition: transform var(--layer-transition);
|
||||||
transform: translate3d(100%, 0, 0);
|
transform: translate3d(100%, 0, 0);
|
||||||
|
|
||||||
:global(.chat-list) {
|
:global(.chat-list) {
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity 250ms ease; // Same as Forum Panel
|
transition: opacity var(--layer-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
&--tabs-hidden .TabList {
|
&--tabs-hidden .TabList {
|
||||||
|
|||||||
@ -102,7 +102,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.SearchInput {
|
.SearchInput {
|
||||||
transition: opacity 250ms ease; // Same as Forum Panel
|
transition: opacity var(--layer-transition);
|
||||||
|
|
||||||
&--hidden {
|
&--hidden {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
36
src/components/left/main/hooks/useCollapseWithForumPanel.ts
Normal file
36
src/components/left/main/hooks/useCollapseWithForumPanel.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { useLayoutEffect } from '../../../../lib/teact/teact';
|
||||||
|
import { fastRaf } from '../../../../util/schedulers';
|
||||||
|
import { ANIMATION_END_DELAY } from '../../../../config';
|
||||||
|
|
||||||
|
const ANIMATION_DURATION = 450;
|
||||||
|
|
||||||
|
// Reduce height of forum chat items when opening Forum Panel
|
||||||
|
export default function useCollapseWithForumPanel(
|
||||||
|
containerRef: React.RefObject<HTMLDivElement>,
|
||||||
|
isForumPanelOpen = false,
|
||||||
|
) {
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const chatEls = Array.from(containerRef.current!.querySelectorAll<HTMLDivElement>('.Chat'));
|
||||||
|
|
||||||
|
chatEls.forEach((chatEl) => {
|
||||||
|
const offsetCollapseDelta = Number(chatEl.dataset.offsetCollapseDelta);
|
||||||
|
chatEl.style.transform = `translateY(${isForumPanelOpen ? offsetCollapseDelta : -offsetCollapseDelta!}px)`;
|
||||||
|
});
|
||||||
|
|
||||||
|
fastRaf(() => {
|
||||||
|
chatEls.forEach((chatEl) => {
|
||||||
|
chatEl.classList.add('animate-collapse');
|
||||||
|
chatEl.style.transform = '';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// Wait one more frame for better animation performance
|
||||||
|
fastRaf(() => {
|
||||||
|
chatEls.forEach((chatEl) => {
|
||||||
|
chatEl.classList.remove('animate-collapse');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, ANIMATION_DURATION + ANIMATION_END_DELAY);
|
||||||
|
}, [containerRef, isForumPanelOpen]);
|
||||||
|
}
|
||||||
@ -94,7 +94,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
--background-color: var(--color-chat-hover);
|
--background-color: var(--color-chat-hover);
|
||||||
|
|||||||
@ -44,13 +44,14 @@ interface OwnProps {
|
|||||||
destructive?: boolean;
|
destructive?: boolean;
|
||||||
multiline?: boolean;
|
multiline?: boolean;
|
||||||
isStatic?: boolean;
|
isStatic?: boolean;
|
||||||
clickArg?: any;
|
|
||||||
contextActions?: MenuItemContextAction[];
|
contextActions?: MenuItemContextAction[];
|
||||||
|
offsetCollapseDelta?: number;
|
||||||
|
withPortalForMenu?: boolean;
|
||||||
onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||||
onClick?: (e: React.MouseEvent<HTMLDivElement>, arg?: any) => void;
|
onClick?: (e: React.MouseEvent<HTMLDivElement>, arg?: any) => void;
|
||||||
|
clickArg?: any;
|
||||||
onSecondaryIconClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
onSecondaryIconClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||||
onDragEnter?: (e: React.DragEvent<HTMLDivElement>) => void;
|
onDragEnter?: (e: React.DragEvent<HTMLDivElement>) => void;
|
||||||
shouldUsePortalForMenu?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListItem: FC<OwnProps> = ({
|
const ListItem: FC<OwnProps> = ({
|
||||||
@ -74,12 +75,13 @@ const ListItem: FC<OwnProps> = ({
|
|||||||
multiline,
|
multiline,
|
||||||
isStatic,
|
isStatic,
|
||||||
contextActions,
|
contextActions,
|
||||||
|
withPortalForMenu,
|
||||||
|
offsetCollapseDelta,
|
||||||
onMouseDown,
|
onMouseDown,
|
||||||
onClick,
|
onClick,
|
||||||
clickArg,
|
clickArg,
|
||||||
onSecondaryIconClick,
|
onSecondaryIconClick,
|
||||||
onDragEnter,
|
onDragEnter,
|
||||||
shouldUsePortalForMenu,
|
|
||||||
}) => {
|
}) => {
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
let containerRef = useRef<HTMLDivElement>(null);
|
let containerRef = useRef<HTMLDivElement>(null);
|
||||||
@ -107,8 +109,8 @@ const ListItem: FC<OwnProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const getLayout = useCallback(
|
const getLayout = useCallback(
|
||||||
() => ({ shouldUsePortalPositioning: shouldUsePortalForMenu }),
|
() => ({ withPortal: withPortalForMenu }),
|
||||||
[shouldUsePortalForMenu],
|
[withPortalForMenu],
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -183,6 +185,7 @@ const ListItem: FC<OwnProps> = ({
|
|||||||
className={fullClassName}
|
className={fullClassName}
|
||||||
dir={lang.isRtl ? 'rtl' : undefined}
|
dir={lang.isRtl ? 'rtl' : undefined}
|
||||||
style={style}
|
style={style}
|
||||||
|
data-offset-collapse-delta={offsetCollapseDelta}
|
||||||
onMouseDown={onMouseDown}
|
onMouseDown={onMouseDown}
|
||||||
onDragEnter={onDragEnter}
|
onDragEnter={onDragEnter}
|
||||||
>
|
>
|
||||||
@ -230,7 +233,7 @@ const ListItem: FC<OwnProps> = ({
|
|||||||
autoClose
|
autoClose
|
||||||
onClose={handleContextMenuClose}
|
onClose={handleContextMenuClose}
|
||||||
onCloseAnimationEnd={handleContextMenuHide}
|
onCloseAnimationEnd={handleContextMenuHide}
|
||||||
shouldUsePortalForMenu={shouldUsePortalForMenu}
|
withPortal={withPortalForMenu}
|
||||||
>
|
>
|
||||||
{contextActions.map((action) => (
|
{contextActions.map((action) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|||||||
@ -41,7 +41,7 @@ type OwnProps = {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onMouseEnter?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
onMouseEnter?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||||
onMouseLeave?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
onMouseLeave?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||||
shouldUsePortalForMenu?: boolean;
|
withPortal?: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ const Menu: FC<OwnProps> = ({
|
|||||||
onMouseEnter,
|
onMouseEnter,
|
||||||
onMouseLeave,
|
onMouseLeave,
|
||||||
shouldSkipTransition,
|
shouldSkipTransition,
|
||||||
shouldUsePortalForMenu,
|
withPortal,
|
||||||
}) => {
|
}) => {
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
let menuRef = useRef<HTMLDivElement>(null);
|
let menuRef = useRef<HTMLDivElement>(null);
|
||||||
@ -161,7 +161,7 @@ const Menu: FC<OwnProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (shouldUsePortalForMenu) {
|
if (withPortal) {
|
||||||
return <Portal>{menu}</Portal>;
|
return <Portal>{menu}</Portal>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -54,6 +54,10 @@ addActionHandler('openChat', (global, actions, payload) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id !== global.forumPanelChatId) {
|
||||||
|
actions.closeForumPanel();
|
||||||
|
}
|
||||||
|
|
||||||
return updateCurrentMessageList(global, id, threadId, type, shouldReplaceHistory);
|
return updateCurrentMessageList(global, id, threadId, type, shouldReplaceHistory);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ interface Layout {
|
|||||||
extraTopPadding?: number;
|
extraTopPadding?: number;
|
||||||
marginSides?: number;
|
marginSides?: number;
|
||||||
extraMarginTop?: number;
|
extraMarginTop?: number;
|
||||||
shouldUsePortalPositioning?: boolean;
|
withPortal?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MENU_POSITION_VISUAL_COMFORT_SPACE_PX = 16;
|
const MENU_POSITION_VISUAL_COMFORT_SPACE_PX = 16;
|
||||||
@ -48,7 +48,7 @@ export default function useContextMenuPosition(
|
|||||||
extraTopPadding = 0,
|
extraTopPadding = 0,
|
||||||
marginSides = 0,
|
marginSides = 0,
|
||||||
extraMarginTop = 0,
|
extraMarginTop = 0,
|
||||||
shouldUsePortalPositioning = false,
|
withPortal = false,
|
||||||
} = getLayout?.() || {};
|
} = getLayout?.() || {};
|
||||||
|
|
||||||
const marginTop = menuEl ? parseInt(getComputedStyle(menuEl).marginTop, 10) + extraMarginTop : undefined;
|
const marginTop = menuEl ? parseInt(getComputedStyle(menuEl).marginTop, 10) + extraMarginTop : undefined;
|
||||||
@ -100,8 +100,8 @@ export default function useContextMenuPosition(
|
|||||||
|
|
||||||
const triggerRect = triggerEl.getBoundingClientRect();
|
const triggerRect = triggerEl.getBoundingClientRect();
|
||||||
|
|
||||||
const addedYForPortalPositioning = (shouldUsePortalPositioning ? triggerRect.top : 0);
|
const addedYForPortalPositioning = (withPortal ? triggerRect.top : 0);
|
||||||
const addedXForPortalPositioning = (shouldUsePortalPositioning ? triggerRect.left : 0);
|
const addedXForPortalPositioning = (withPortal ? triggerRect.left : 0);
|
||||||
|
|
||||||
const left = (horizontalPosition === 'left'
|
const left = (horizontalPosition === 'left'
|
||||||
? Math.max(MENU_POSITION_VISUAL_COMFORT_SPACE_PX, Math.min(
|
? Math.max(MENU_POSITION_VISUAL_COMFORT_SPACE_PX, Math.min(
|
||||||
|
|||||||
@ -88,6 +88,21 @@
|
|||||||
@include overflow-y-overlay();
|
@include overflow-y-overlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.forum-panel-open {
|
||||||
|
.info {
|
||||||
|
transform: translateX(-25%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Chat[dir="rtl"] .info {
|
||||||
|
transform: translateX(25%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ListItem-button {
|
||||||
|
height: 4.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.scroll-container {
|
.scroll-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,7 +150,6 @@ $color-message-reaction-own-hover: #b5e0a4;
|
|||||||
|
|
||||||
--color-chat-hover: #{$color-chat-hover};
|
--color-chat-hover: #{$color-chat-hover};
|
||||||
--color-chat-active: #{$color-chat-active};
|
--color-chat-active: #{$color-chat-active};
|
||||||
--color-chat-active-greyed: #60a7f0;
|
|
||||||
--color-item-active: #{$color-item-active};
|
--color-item-active: #{$color-item-active};
|
||||||
|
|
||||||
--color-selection-highlight: #{$color-selection};
|
--color-selection-highlight: #{$color-selection};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user