Chat: Use normal list item height for forum

This commit is contained in:
Alexander Zinchuk 2023-02-28 18:43:53 +01:00
parent 37b9836739
commit f18548d4a3
12 changed files with 80 additions and 114 deletions

View File

@ -44,6 +44,7 @@
.loading { .loading {
color: var(--color-text-secondary); color: var(--color-text-secondary);
line-height: 1.25rem;
} }
.other-column, .main-column { .other-column, .main-column {
@ -102,6 +103,7 @@
.title { .title {
margin-left: 0.25rem; margin-left: 0.25rem;
font-size: 0.9375rem; font-size: 0.9375rem;
line-height: 1.25rem;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
@ -115,6 +117,8 @@
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
line-height: 1.25rem;
height: 1.25rem;
} }
.ellipsis { .ellipsis {
@ -145,6 +149,10 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
:global(.last-message) {
line-height: 1.25rem !important;
}
} }
.reverse-corner { .reverse-corner {

View File

@ -90,7 +90,7 @@ const ChatForumLastMessage: FC<OwnProps> = ({
style={overwrittenWidth ? `--overwritten-width: ${overwrittenWidth}px` : undefined} style={overwrittenWidth ? `--overwritten-width: ${overwrittenWidth}px` : undefined}
> >
{lastActiveTopic && ( {lastActiveTopic && (
<span className={styles.titleRow}> <div className={styles.titleRow}>
<div <div
className={buildClassName( className={buildClassName(
styles.mainColumn, styles.mainColumn,
@ -129,10 +129,10 @@ const ChatForumLastMessage: FC<OwnProps> = ({
</div> </div>
<div className={styles.ellipsis} /> <div className={styles.ellipsis} />
</span> </div>
)} )}
{!lastActiveTopic && <div className={buildClassName(styles.titleRow, styles.loading)}>{lang('Loading')}</div>} {!lastActiveTopic && <div className={buildClassName(styles.titleRow, styles.loading)}>{lang('Loading')}</div>}
<span <div
className={buildClassName(styles.lastMessage, lastActiveTopic?.unreadCount && styles.unread)} className={buildClassName(styles.lastMessage, lastActiveTopic?.unreadCount && styles.unread)}
ref={lastMessageRef} ref={lastMessageRef}
onMouseDown={handleOpenTopic} onMouseDown={handleOpenTopic}
@ -143,7 +143,7 @@ const ChatForumLastMessage: FC<OwnProps> = ({
<div className={styles.after} /> <div className={styles.after} />
</div> </div>
)} )}
</span> </div>
</div> </div>
); );

View File

@ -1,9 +1,7 @@
.LastMessageMeta { .LastMessageMeta {
margin-right: 0.1875rem; margin-right: 0.1875rem;
padding: 0.3125rem 0 0.125rem;
flex-shrink: 0; flex-shrink: 0;
font-size: 0.75rem; font-size: 0.75rem;
line-height: 1;
display: flex; display: flex;
align-items: center; align-items: center;
@ -19,6 +17,5 @@
.time { .time {
color: var(--color-text-meta); color: var(--color-text-meta);
line-height: 1.125rem;
} }
} }

View File

@ -154,7 +154,6 @@ const Archive: FC<OwnProps> = ({
'chat-item-archive', 'chat-item-archive',
)} )}
buttonClassName={styles.button} buttonClassName={styles.button}
offsetCollapseDelta={0}
contextActions={contextActions} contextActions={contextActions}
withPortalForMenu withPortalForMenu
> >

View File

@ -25,11 +25,6 @@
transition: transform 0.2s ease-out; transition: transform 0.2s ease-out;
} }
&.animate-collapse {
will-change: transform;
transition: transform var(--layer-transition);
}
&:hover, &:hover,
&.ListItem.has-menu-open { &.ListItem.has-menu-open {
.Avatar.online::after { .Avatar.online::after {
@ -160,6 +155,15 @@
&.forum { &.forum {
--color-chat-username: var(--color-text); --color-chat-username: var(--color-text);
.ListItem-button {
padding-top: 0.25rem;
padding-bottom: 0.375rem;
}
.title {
line-height: 1.375rem;
}
} }
.ripple-container { .ripple-container {
@ -167,9 +171,10 @@
} }
.status { .status {
height: 3.375rem;
position: relative; position: relative;
flex-shrink: 0; align-self: stretch;
display: flex;
align-items: center;
z-index: 1; z-index: 1;
background: var(--background-color); background: var(--background-color);
} }
@ -198,10 +203,6 @@
.info { .info {
transition: opacity 300ms ease, transform var(--layer-transition); transition: opacity 300ms ease, transform var(--layer-transition);
.subtitle {
margin-top: -0.125rem;
}
.icon-muted { .icon-muted {
font-size: 1.25rem; font-size: 1.25rem;
margin-top: -0.0625rem; margin-top: -0.0625rem;

View File

@ -66,7 +66,6 @@ type OwnProps = {
animationType: ChatAnimationTypes; animationType: ChatAnimationTypes;
isPinned?: boolean; isPinned?: boolean;
offsetTop: number; offsetTop: number;
offsetCollapseDelta: number;
observeIntersection?: ObserveFn; observeIntersection?: ObserveFn;
onDragEnter?: (chatId: string) => void; onDragEnter?: (chatId: string) => void;
}; };
@ -111,7 +110,6 @@ const Chat: FC<OwnProps & StateProps> = ({
actionTargetMessage, actionTargetMessage,
actionTargetChatId, actionTargetChatId,
offsetTop, offsetTop,
offsetCollapseDelta,
draft, draft,
animationLevel, animationLevel,
isSelected, isSelected,
@ -233,7 +231,6 @@ const Chat: FC<OwnProps & StateProps> = ({
contextActions={contextActions} contextActions={contextActions}
onClick={handleClick} onClick={handleClick}
onDragEnter={handleDragEnter} onDragEnter={handleDragEnter}
offsetCollapseDelta={offsetCollapseDelta}
withPortalForMenu withPortalForMenu
> >
<div className="status"> <div className="status">

View File

@ -1,7 +1,7 @@
import React, { import React, {
memo, useEffect, useRef, useCallback, useMemo, memo, useEffect, useRef, useCallback,
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { getActions, getGlobal } from '../../../global'; import { getActions } from '../../../global';
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import type { FolderEditDispatch } from '../../../hooks/reducers/useFoldersReducer'; import type { FolderEditDispatch } from '../../../hooks/reducers/useFoldersReducer';
@ -11,13 +11,13 @@ import type { GlobalState } from '../../../global/types';
import { import {
ALL_FOLDER_ID, ALL_FOLDER_ID,
ARCHIVED_FOLDER_ID, ARCHIVE_MINIMIZED_HEIGHT, CHAT_HEIGHT_FORUM_PX, ARCHIVED_FOLDER_ID,
ARCHIVE_MINIMIZED_HEIGHT,
CHAT_HEIGHT_PX, CHAT_HEIGHT_PX,
CHAT_LIST_SLICE, CHAT_LIST_SLICE,
} from '../../../config'; } from '../../../config';
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 buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import useInfiniteScroll from '../../../hooks/useInfiniteScroll'; import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
@ -26,7 +26,6 @@ import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver'
import { useHotkeys } from '../../../hooks/useHotkeys'; import { useHotkeys } from '../../../hooks/useHotkeys';
import useDebouncedCallback from '../../../hooks/useDebouncedCallback'; import useDebouncedCallback from '../../../hooks/useDebouncedCallback';
import useChatOrderDiff from './hooks/useChatOrderDiff'; import useChatOrderDiff from './hooks/useChatOrderDiff';
import useCollapseWithForumPanel from './hooks/useCollapseWithForumPanel';
import InfiniteScroll from '../../ui/InfiniteScroll'; import InfiniteScroll from '../../ui/InfiniteScroll';
import Loading from '../../ui/Loading'; import Loading from '../../ui/Loading';
@ -134,8 +133,6 @@ const ChatList: FC<OwnProps> = ({
throttleMs: INTERSECTION_THROTTLE, throttleMs: INTERSECTION_THROTTLE,
}); });
useCollapseWithForumPanel(containerRef, isForumPanelOpen);
const handleArchivedClick = useCallback(() => { const handleArchivedClick = useCallback(() => {
onLeftColumnContentChange(LeftColumnContent.Archived); onLeftColumnContentChange(LeftColumnContent.Archived);
closeForumPanel(); closeForumPanel();
@ -165,32 +162,14 @@ const ChatList: FC<OwnProps> = ({
shouldIgnoreDragRef.current = true; shouldIgnoreDragRef.current = true;
}, []); }, []);
const viewportOffsetPx = useMemo(() => {
if (!viewportIds?.length) return 0;
const global = getGlobal();
const viewportOffset = orderedIds!.indexOf(viewportIds![0]);
return archiveHeight + orderedIds!.reduce((acc, id, i) => {
if (i >= viewportOffset) {
return acc;
}
return acc + (selectChat(global, id)!.isForum ? CHAT_HEIGHT_FORUM_PX : CHAT_HEIGHT_PX);
}, 0);
}, [archiveHeight, orderedIds, viewportIds]);
function renderChats() { function renderChats() {
const viewportOffset = orderedIds!.indexOf(viewportIds![0]); const viewportOffset = orderedIds!.indexOf(viewportIds![0]);
const global = getGlobal();
const pinnedCount = getPinnedChatsCount(resolvedFolderId) || 0; const pinnedCount = getPinnedChatsCount(resolvedFolderId) || 0;
let currentChatListHeight = viewportOffsetPx;
return viewportIds!.map((id, i) => { return viewportIds!.map((id, i) => {
const isPinned = viewportOffset + i < pinnedCount; const isPinned = viewportOffset + i < pinnedCount;
const expendedOffsetTop = currentChatListHeight; const offsetTop = archiveHeight + (viewportOffset + i) * CHAT_HEIGHT_PX;
const collapsedOffsetTop = archiveHeight + (viewportOffset + i) * CHAT_HEIGHT_PX;
currentChatListHeight += (selectChat(global, id)?.isForum ? CHAT_HEIGHT_FORUM_PX : CHAT_HEIGHT_PX);
return ( return (
<Chat <Chat
@ -201,8 +180,7 @@ const ChatList: FC<OwnProps> = ({
folderId={folderId} folderId={folderId}
animationType={getAnimationType(id)} animationType={getAnimationType(id)}
orderDiff={orderDiffById[id]} orderDiff={orderDiffById[id]}
offsetTop={isForumPanelOpen ? collapsedOffsetTop : expendedOffsetTop} offsetTop={offsetTop}
offsetCollapseDelta={expendedOffsetTop - collapsedOffsetTop}
observeIntersection={observe} observeIntersection={observe}
onDragEnter={handleDragEnter} onDragEnter={handleDragEnter}
/> />

View File

@ -1,36 +0,0 @@
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

@ -3,7 +3,7 @@
body.is-ios &, body.is-ios &,
body.is-android & { body.is-android & {
&:not(:last-of-type)::after { &::after {
content: ""; content: "";
position: absolute; position: absolute;
bottom: 0; bottom: 0;
@ -14,6 +14,10 @@
box-shadow: inset 0 -0.03125rem 0 0 var(--color-dividers); box-shadow: inset 0 -0.03125rem 0 0 var(--color-dividers);
} }
&:last-of-type::after {
display: none;
}
&.small-icon::after { &.small-icon::after {
left: 3.875rem; left: 3.875rem;
} }
@ -23,11 +27,9 @@
} }
} }
body.is-android & { body.is-android &::after {
&:not(:last-of-type)::after { /* stylelint-disable-next-line plugin/whole-pixel */
/* stylelint-disable-next-line plugin/whole-pixel */ box-shadow: inset 0 -0.03125rem 0 0 var(--color-dividers-android);
box-shadow: inset 0 -0.03125rem 0 0 var(--color-dividers-android);
}
} }
.ListItem-button { .ListItem-button {
@ -38,10 +40,10 @@
box-shadow: none !important; box-shadow: none !important;
outline: none !important; outline: none !important;
display: flex; display: flex;
align-items: center;
padding: 1rem; padding: 1rem;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
line-height: 1.5rem;
white-space: nowrap; white-space: nowrap;
color: var(--color-text); color: var(--color-text);
border-radius: var(--border-radius-default); border-radius: var(--border-radius-default);
@ -60,6 +62,10 @@
} }
} }
.title, .subtitle {
line-height: 1.5rem;
}
.user-status, .user-status,
.group-status, .group-status,
.title, .title,
@ -181,12 +187,11 @@
} }
.Avatar { .Avatar {
flex-shrink: 0;
margin-right: 0.5rem; margin-right: 0.5rem;
} }
.info { .info {
flex-grow: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
@ -214,7 +219,6 @@
.status, .status,
.typing-status { .typing-status {
font-size: 1rem; font-size: 1rem;
line-height: 1.6875rem;
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
@ -238,9 +242,15 @@
.ChatInfo { .ChatInfo {
display: flex; display: flex;
align-items: center; align-items: center;
flex-grow: 1; flex: 1;
overflow: hidden; overflow: hidden;
.info {
display: flex;
flex-direction: column;
justify-content: center;
}
.custom-title { .custom-title {
padding-inline-start: 1rem; padding-inline-start: 1rem;
font-size: 0.875rem; font-size: 0.875rem;

View File

@ -54,7 +54,6 @@ interface OwnProps {
multiline?: boolean; multiline?: boolean;
isStatic?: boolean; isStatic?: boolean;
contextActions?: MenuItemContextAction[]; contextActions?: MenuItemContextAction[];
offsetCollapseDelta?: number;
withPortalForMenu?: boolean; withPortalForMenu?: boolean;
href?: string; href?: string;
onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void; onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;
@ -85,7 +84,6 @@ const ListItem: FC<OwnProps> = ({
isStatic, isStatic,
contextActions, contextActions,
withPortalForMenu, withPortalForMenu,
offsetCollapseDelta,
href, href,
onMouseDown, onMouseDown,
onClick, onClick,
@ -216,7 +214,6 @@ 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}
> >

View File

@ -63,7 +63,6 @@ export const MESSAGE_LIST_VIEWPORT_LIMIT = MESSAGE_LIST_SLICE * 2;
export const ARCHIVE_MINIMIZED_HEIGHT = 36; export const ARCHIVE_MINIMIZED_HEIGHT = 36;
export const CHAT_HEIGHT_PX = 72; export const CHAT_HEIGHT_PX = 72;
export const CHAT_HEIGHT_FORUM_PX = 94;
export const TOPIC_HEIGHT_PX = 65; export const TOPIC_HEIGHT_PX = 65;
export const CHAT_LIST_SLICE = isBigScreen ? 30 : 25; export const CHAT_LIST_SLICE = isBigScreen ? 30 : 25;
export const CHAT_LIST_LOAD_SLICE = 100; export const CHAT_LIST_LOAD_SLICE = 100;

View File

@ -93,20 +93,8 @@
} }
.Chat[dir="rtl"] .info { .Chat[dir="rtl"] .info {
transform: translateX(25%); transform: translateX(20%);
} }
.group .ListItem-button {
height: 4.5rem;
}
}
.scroll-container {
position: relative;
}
.ListItem.chat-item-clickable {
margin: 0;
} }
@media (max-width: 600px) { @media (max-width: 600px) {
@ -114,11 +102,39 @@
padding-right: 0; padding-right: 0;
} }
.scroll-container {
position: relative;
}
.no-results { .no-results {
color: var(--color-text-meta); color: var(--color-text-meta);
margin-top: 2rem; margin-top: 2rem;
text-align: center; text-align: center;
} }
.Avatar {
transition: transform var(--layer-transition);
}
.ListItem {
&.chat-item-clickable {
margin: 0;
}
}
body.is-ios &,
body.is-android & {
.ListItem::after {
opacity: 1;
transition: opacity var(--layer-transition);
}
&.forum-panel-open {
.ListItem::after {
opacity: 0;
}
}
}
} }
// Used by Avatar and ProfilePhoto components // Used by Avatar and ProfilePhoto components