Forum Panel: Various optimizations

This commit is contained in:
Alexander Zinchuk 2023-01-07 19:09:03 +01:00
parent d65f1d99fc
commit 556c4c0b21
17 changed files with 203 additions and 154 deletions

View File

@ -68,7 +68,7 @@ const ArchivedChats: FC<OwnProps> = ({
</Button>
{shouldRenderTitle && <h3 className={titleClassNames}>{lang('ArchivedChats')}</h3>}
</div>
<ChatList folderType="archived" isActive={isActive} />
<ChatList folderType="archived" isActive={isActive} isForumPanelOpen={isForumPanelOpen} />
{shouldRenderForumPanel && (
<ForumPanel
isOpen={isForumPanelOpen}

View 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));

View File

@ -15,12 +15,17 @@
&.animate-opacity {
will-change: opacity;
transition: opacity 250ms ease;
transition: opacity 0.2s ease-out;
}
&.animate-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,
@ -29,7 +34,7 @@
border-color: var(--color-chat-hover);
}
.status-badge-wrapper {
.avatar-badge-wrapper {
--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 {
padding-bottom: 0.5rem;
}
@ -55,17 +70,17 @@
}
}
&.active-forum {
.status-badge-wrapper {
&.selected-forum {
.avatar-badge-wrapper {
--outline-color: var(--color-chat-hover);
}
}
}
@media (min-width: 600px) {
&.active-forum.forum,
&.active-forum.forum:hover {
.status-badge-wrapper {
&.selected-forum.forum,
&.selected-forum.forum:hover {
.avatar-badge-wrapper {
--outline-color: var(--color-chat-hover);
}
}
@ -111,7 +126,6 @@
}
.Badge:not(.pinned) {
background: var(--color-white);
color: var(--color-chat-active);
}
@ -120,35 +134,18 @@
background: #FFFFFF33;
}
.status-badge-wrapper-visible .Badge:not(.pinned).muted {
background: var(--color-chat-active-greyed);
.avatar-badge-wrapper .Badge:not(.pinned) {
--outline-color: transparent;
}
.status-badge-wrapper-visible .Badge:not(.pinned):not(.muted) {
--outline-color: transparent;
.avatar-badge-wrapper .Badge:not(.pinned).muted {
background: var(--color-gray);
}
}
}
&.smaller .ListItem-button {
height: 4.5rem;
}
&.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);
&.selected-forum {
--background-color: var(--color-chat-hover) !important;
}
@media (max-width: 600px) {
@ -169,7 +166,7 @@
background: var(--background-color);
}
.status-badge-wrapper {
.avatar-badge-wrapper {
position: absolute;
bottom: 0;
right: 0.5rem;
@ -182,12 +179,12 @@
}
.Badge-transition {
transition: opacity 250ms ease, transform 250ms ease; // Same as Forum Panel
transition: opacity var(--layer-transition), transform var(--layer-transition);
}
}
.info {
transition: opacity 250ms ease, transform 250ms ease; // Same as Forum Panel
transition: opacity 300ms ease, transform var(--layer-transition);
.subtitle {
margin-top: -0.125rem;
@ -316,19 +313,5 @@
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%);
}
}

View File

@ -1,7 +1,5 @@
import type { FC } from '../../../lib/teact/teact';
import React, {
memo, useCallback, useEffect, useLayoutEffect, useRef,
} from '../../../lib/teact/teact';
import React, { memo, useCallback, useEffect } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
@ -18,7 +16,6 @@ import type {
import type { AnimationLevel } from '../../../types';
import type { ChatAnimationTypes } from './hooks';
import { ANIMATION_END_DELAY } from '../../../config';
import { MAIN_THREAD_ID } from '../../../api/types';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import {
@ -40,40 +37,35 @@ import {
selectIsDefaultEmojiStatusPack,
selectTopicFromMessage,
selectThreadParam,
selectIsForumPanelOpen,
} from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { fastRaf } from '../../../util/schedulers';
import buildStyle from '../../../util/buildStyle';
import useChatContextActions from '../../../hooks/useChatContextActions';
import useFlag from '../../../hooks/useFlag';
import useChatListEntry from './hooks/useChatListEntry';
import { useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import usePrevious from '../../../hooks/usePrevious';
import ListItem from '../../ui/ListItem';
import Avatar from '../../common/Avatar';
import LastMessageMeta from '../../common/LastMessageMeta';
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 FullNameTitle from '../../common/FullNameTitle';
import ChatFolderModal from '../ChatFolderModal.async';
import ChatCallStatus from './ChatCallStatus';
import Badge from './Badge';
import AvatarBadge from './AvatarBadge';
import './Chat.scss';
const TRANSFORM_TO_TOPIC_LIST_ANIMATION_DELAY = 300;
type OwnProps = {
chatId: string;
folderId?: number;
orderDiff: number;
animationType: ChatAnimationTypes;
isPinned?: boolean;
offsetTopInSmallerMode: number;
offsetTop: number;
offsetCollapseDelta: number;
observeIntersection?: ObserveFn;
onDragEnter?: (chatId: string) => void;
};
@ -92,13 +84,12 @@ type StateProps = {
draft?: ApiFormattedText;
animationLevel?: AnimationLevel;
isSelected?: boolean;
isForumPanelActive?: boolean;
isSelectedForum?: boolean;
canScrollDown?: boolean;
canChangeFolder?: boolean;
lastSyncTime?: number;
lastMessageTopic?: ApiTopic;
typingStatus?: ApiTypingStatus;
forumPanelChatId?: string;
};
const Chat: FC<OwnProps & StateProps> = ({
@ -118,24 +109,22 @@ const Chat: FC<OwnProps & StateProps> = ({
lastMessageOutgoingStatus,
actionTargetMessage,
actionTargetChatId,
offsetTopInSmallerMode,
offsetTop,
offsetCollapseDelta,
draft,
animationLevel,
isSelected,
isForumPanelActive,
isSelectedForum,
canScrollDown,
canChangeFolder,
lastSyncTime,
lastMessageTopic,
typingStatus,
forumPanelChatId,
onDragEnter,
}) => {
const {
openChat,
openForumPanel,
closeForumPanel,
focusLastMessage,
loadTopics,
} = getActions();
@ -161,27 +150,24 @@ const Chat: FC<OwnProps & StateProps> = ({
lastMessageTopic,
lastMessageSender,
observeIntersection,
animationType,
animationLevel,
orderDiff,
});
const handleClick = useCallback(() => {
if (chat?.isForum) {
if (isForum) {
openForumPanel({ chatId });
return;
}
if (forumPanelChatId) closeForumPanel();
openChat({ id: chatId, shouldReplaceHistory: true }, { forceOnHeavyAnimation: true });
if (isSelected && canScrollDown) {
focusLastMessage();
}
}, [
chat?.isForum, forumPanelChatId, closeForumPanel, openChat, chatId, isSelected, canScrollDown, openForumPanel,
focusLastMessage,
isForum, openChat, chatId, isSelected, canScrollDown, openForumPanel, focusLastMessage,
]);
const handleDragEnter = useCallback((e) => {
@ -225,31 +211,6 @@ const Chat: FC<OwnProps & StateProps> = ({
}
}, [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) {
return undefined;
}
@ -259,23 +220,20 @@ const Chat: FC<OwnProps & StateProps> = ({
isUserId(chatId) ? 'private' : 'group',
isForum && 'forum',
isSelected && 'selected',
isForumPanelActive && 'smaller',
isOnForumPanel && 'active-forum',
isSelectedForum && 'selected-forum',
);
const chatTop = isForumPanelActive ? (offsetTop - offsetTopInSmallerMode) : offsetTop;
const offsetAnimate = isForumPanelActive ? offsetTopInSmallerMode : -offsetTopInSmallerMode;
return (
<ListItem
ref={ref}
className={className}
style={buildStyle(`top: ${chatTop}px`, isAnimatingRef.current && `transform: translateY(${offsetAnimate}px)`)}
style={`top: ${offsetTop}px`}
ripple={!isForum && !IS_SINGLE_COLUMN_LAYOUT}
contextActions={contextActions}
onClick={handleClick}
onDragEnter={handleDragEnter}
shouldUsePortalForMenu={isForumPanelActive}
offsetCollapseDelta={offsetCollapseDelta}
withPortalForMenu
>
<div className="status">
<Avatar
@ -288,9 +246,7 @@ const Chat: FC<OwnProps & StateProps> = ({
withVideo
observeIntersection={observeIntersection}
/>
<div className="status-badge-wrapper">
<Badge chat={chat} isMuted={isMuted} shouldShowOnlyMostImportant forceHidden={!isForumPanelActive} />
</div>
<AvatarBadge chatId={chatId} />
{chat.isCallActive && chat.isCallNotEmpty && (
<ChatCallStatus isSelected={isSelected} isActive={animationLevel !== 0} />
)}
@ -368,8 +324,8 @@ export default memo(withGlobal<OwnProps>(
threadId: currentThreadId,
type: messageListType,
} = selectCurrentMessageList(global) || {};
const isForumPanelActive = selectIsForumPanelOpen(global);
const isSelected = chatId === currentChatId && currentThreadId === MAIN_THREAD_ID;
const isSelectedForum = chatId === global.forumPanelChatId;
const user = privateChatUserId ? selectUser(global, privateChatUserId) : undefined;
const userStatus = privateChatUserId ? selectUserStatus(global, privateChatUserId) : undefined;
@ -388,8 +344,8 @@ export default memo(withGlobal<OwnProps>(
actionTargetMessage,
draft: selectDraft(global, chatId, MAIN_THREAD_ID),
animationLevel: global.settings.byKey.animationLevel,
isForumPanelActive,
isSelected,
isSelectedForum,
canScrollDown: isSelected && messageListType === 'thread',
canChangeFolder: (global.chatFolders.orderedIds?.length || 0) > 1,
lastSyncTime: global.lastSyncTime,
@ -401,7 +357,6 @@ export default memo(withGlobal<OwnProps>(
isEmojiStatusColored,
lastMessageTopic,
typingStatus,
forumPanelChatId: global.forumPanelChatId,
};
},
)(Chat));

View File

@ -22,6 +22,7 @@ import { useFolderManagerForUnreadCounters } from '../../../hooks/useFolderManag
import Transition from '../../ui/Transition';
import TabList from '../../ui/TabList';
import ChatList from './ChatList';
import { selectIsForumPanelOpen } from '../../../global/selectors';
type OwnProps = {
onScreenSelect: (screen: SettingsScreens) => void;
@ -34,6 +35,7 @@ type StateProps = {
orderedFolderIds?: number[];
activeChatFolder: number;
currentUserId?: string;
isForumPanelOpen?: boolean;
lastSyncTime?: number;
shouldSkipHistoryAnimations?: boolean;
maxFolders: number;
@ -49,6 +51,7 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
orderedFolderIds,
activeChatFolder,
currentUserId,
isForumPanelOpen,
lastSyncTime,
shouldSkipHistoryAnimations,
maxFolders,
@ -195,27 +198,17 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
function renderCurrentTab(isActive: boolean) {
const activeFolder = Object.values(chatFoldersById)
.find(({ id }) => id === folderTabs![activeChatFolder].id);
if (!activeFolder || isInAllChatsFolder) {
return (
<ChatList
folderType="all"
isActive={isActive}
lastSyncTime={lastSyncTime}
foldersDispatch={foldersDispatch}
onScreenSelect={onScreenSelect}
/>
);
}
const isFolder = activeFolder && !isInAllChatsFolder;
return (
<ChatList
folderType="folder"
folderId={activeFolder.id}
folderType={isFolder ? 'folder' : 'all'}
folderId={isFolder ? activeFolder.id : undefined}
isActive={isActive}
isForumPanelOpen={isForumPanelOpen}
lastSyncTime={lastSyncTime}
onScreenSelect={onScreenSelect}
foldersDispatch={foldersDispatch}
onScreenSelect={onScreenSelect}
/>
);
}
@ -259,16 +252,15 @@ export default memo(withGlobal<OwnProps>(
shouldSkipHistoryAnimations,
} = global;
const maxFolders = selectCurrentLimit(global, 'dialogFilters');
return {
chatFoldersById,
orderedFolderIds,
activeChatFolder,
currentUserId,
isForumPanelOpen: selectIsForumPanelOpen(global),
lastSyncTime,
shouldSkipHistoryAnimations,
maxFolders,
maxFolders: selectCurrentLimit(global, 'dialogFilters'),
};
},
)(ChatFolders));

View File

@ -16,6 +16,7 @@ import {
import { IS_MAC_OS, IS_PWA } from '../../../util/environment';
import { getPinnedChatsCount, getOrderKey } from '../../../util/folderManager';
import { selectChat } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
import { useFolderManagerForOrderedIds } from '../../../hooks/useFolderManager';
@ -28,11 +29,13 @@ import InfiniteScroll from '../../ui/InfiniteScroll';
import Loading from '../../ui/Loading';
import Chat from './Chat';
import EmptyFolder from './EmptyFolder';
import useCollapseWithForumPanel from './hooks/useCollapseWithForumPanel';
type OwnProps = {
folderType: 'all' | 'archived' | 'folder';
folderId?: number;
isActive: boolean;
isForumPanelOpen?: boolean;
lastSyncTime?: number;
foldersDispatch?: FolderEditDispatch;
onScreenSelect?: (screen: SettingsScreens) => void;
@ -45,6 +48,7 @@ const ChatList: FC<OwnProps> = ({
folderType,
folderId,
isActive,
isForumPanelOpen,
foldersDispatch,
onScreenSelect,
}) => {
@ -105,6 +109,8 @@ const ChatList: FC<OwnProps> = ({
throttleMs: INTERSECTION_THROTTLE,
});
useCollapseWithForumPanel(containerRef, isForumPanelOpen);
const handleDragEnter = useDebouncedCallback((chatId: string) => {
if (shouldIgnoreDragRef.current) {
shouldIgnoreDragRef.current = false;
@ -143,8 +149,9 @@ const ChatList: FC<OwnProps> = ({
return viewportIds!.map((id, i) => {
const isPinned = viewportOffset + i < pinnedCount;
const chatTop = currentChatListHeight;
const chatTopSmaller = (viewportOffset + i) * CHAT_HEIGHT_PX;
const expendedOffsetTop = currentChatListHeight;
const collapsedOffsetTop = (viewportOffset + i) * CHAT_HEIGHT_PX;
currentChatListHeight += (selectChat(global, id)!.isForum ? CHAT_HEIGHT_FORUM_PX : CHAT_HEIGHT_PX);
return (
@ -156,8 +163,8 @@ const ChatList: FC<OwnProps> = ({
folderId={folderId}
animationType={getAnimationType(id)}
orderDiff={orderDiffById[id]}
offsetTop={chatTop}
offsetTopInSmallerMode={chatTop - chatTopSmaller}
offsetTop={isForumPanelOpen ? collapsedOffsetTop : expendedOffsetTop}
offsetCollapseDelta={expendedOffsetTop - collapsedOffsetTop}
observeIntersection={observe}
onDragEnter={handleDragEnter}
/>
@ -167,7 +174,7 @@ const ChatList: FC<OwnProps> = ({
return (
<InfiniteScroll
className="chat-list custom-scroll"
className={buildClassName('chat-list custom-scroll', isForumPanelOpen && 'forum-panel-open')}
ref={containerRef}
items={viewportIds}
preloadBackwards={CHAT_LIST_SLICE}

View File

@ -10,6 +10,10 @@
display: flex;
flex-direction: column;
@media (max-width: 600px) {
left: 4.3125rem;
}
&.rtl {
left: 0;
right: 4.75rem;
@ -18,7 +22,7 @@
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);
:global(.chat-list) {

View File

@ -35,7 +35,7 @@
z-index: 1;
opacity: 1;
transition: opacity 250ms ease; // Same as Forum Panel
transition: opacity var(--layer-transition);
}
&--tabs-hidden .TabList {

View File

@ -102,7 +102,7 @@
}
.SearchInput {
transition: opacity 250ms ease; // Same as Forum Panel
transition: opacity var(--layer-transition);
&--hidden {
opacity: 0;

View 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]);
}

View File

@ -94,7 +94,6 @@
}
@media (hover: hover) {
&:hover,
&:focus {
--background-color: var(--color-chat-hover);

View File

@ -44,13 +44,14 @@ interface OwnProps {
destructive?: boolean;
multiline?: boolean;
isStatic?: boolean;
clickArg?: any;
contextActions?: MenuItemContextAction[];
offsetCollapseDelta?: number;
withPortalForMenu?: boolean;
onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;
onClick?: (e: React.MouseEvent<HTMLDivElement>, arg?: any) => void;
clickArg?: any;
onSecondaryIconClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
onDragEnter?: (e: React.DragEvent<HTMLDivElement>) => void;
shouldUsePortalForMenu?: boolean;
}
const ListItem: FC<OwnProps> = ({
@ -74,12 +75,13 @@ const ListItem: FC<OwnProps> = ({
multiline,
isStatic,
contextActions,
withPortalForMenu,
offsetCollapseDelta,
onMouseDown,
onClick,
clickArg,
onSecondaryIconClick,
onDragEnter,
shouldUsePortalForMenu,
}) => {
// eslint-disable-next-line no-null/no-null
let containerRef = useRef<HTMLDivElement>(null);
@ -107,8 +109,8 @@ const ListItem: FC<OwnProps> = ({
);
const getLayout = useCallback(
() => ({ shouldUsePortalPositioning: shouldUsePortalForMenu }),
[shouldUsePortalForMenu],
() => ({ withPortal: withPortalForMenu }),
[withPortalForMenu],
);
const {
@ -183,6 +185,7 @@ const ListItem: FC<OwnProps> = ({
className={fullClassName}
dir={lang.isRtl ? 'rtl' : undefined}
style={style}
data-offset-collapse-delta={offsetCollapseDelta}
onMouseDown={onMouseDown}
onDragEnter={onDragEnter}
>
@ -230,7 +233,7 @@ const ListItem: FC<OwnProps> = ({
autoClose
onClose={handleContextMenuClose}
onCloseAnimationEnd={handleContextMenuHide}
shouldUsePortalForMenu={shouldUsePortalForMenu}
withPortal={withPortalForMenu}
>
{contextActions.map((action) => (
<MenuItem

View File

@ -41,7 +41,7 @@ type OwnProps = {
onClose: () => void;
onMouseEnter?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
onMouseLeave?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
shouldUsePortalForMenu?: boolean;
withPortal?: boolean;
children: React.ReactNode;
};
@ -70,7 +70,7 @@ const Menu: FC<OwnProps> = ({
onMouseEnter,
onMouseLeave,
shouldSkipTransition,
shouldUsePortalForMenu,
withPortal,
}) => {
// eslint-disable-next-line no-null/no-null
let menuRef = useRef<HTMLDivElement>(null);
@ -161,7 +161,7 @@ const Menu: FC<OwnProps> = ({
</div>
);
if (shouldUsePortalForMenu) {
if (withPortal) {
return <Portal>{menu}</Portal>;
}

View File

@ -54,6 +54,10 @@ addActionHandler('openChat', (global, actions, payload) => {
};
}
if (id !== global.forumPanelChatId) {
actions.closeForumPanel();
}
return updateCurrentMessageList(global, id, threadId, type, shouldReplaceHistory);
});

View File

@ -6,7 +6,7 @@ interface Layout {
extraTopPadding?: number;
marginSides?: number;
extraMarginTop?: number;
shouldUsePortalPositioning?: boolean;
withPortal?: boolean;
}
const MENU_POSITION_VISUAL_COMFORT_SPACE_PX = 16;
@ -48,7 +48,7 @@ export default function useContextMenuPosition(
extraTopPadding = 0,
marginSides = 0,
extraMarginTop = 0,
shouldUsePortalPositioning = false,
withPortal = false,
} = getLayout?.() || {};
const marginTop = menuEl ? parseInt(getComputedStyle(menuEl).marginTop, 10) + extraMarginTop : undefined;
@ -100,8 +100,8 @@ export default function useContextMenuPosition(
const triggerRect = triggerEl.getBoundingClientRect();
const addedYForPortalPositioning = (shouldUsePortalPositioning ? triggerRect.top : 0);
const addedXForPortalPositioning = (shouldUsePortalPositioning ? triggerRect.left : 0);
const addedYForPortalPositioning = (withPortal ? triggerRect.top : 0);
const addedXForPortalPositioning = (withPortal ? triggerRect.left : 0);
const left = (horizontalPosition === 'left'
? Math.max(MENU_POSITION_VISUAL_COMFORT_SPACE_PX, Math.min(

View File

@ -88,6 +88,21 @@
@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 {
position: relative;
}

View File

@ -150,7 +150,6 @@ $color-message-reaction-own-hover: #b5e0a4;
--color-chat-hover: #{$color-chat-hover};
--color-chat-active: #{$color-chat-active};
--color-chat-active-greyed: #60a7f0;
--color-item-active: #{$color-item-active};
--color-selection-highlight: #{$color-selection};