diff --git a/web/chat/chat-thread-list.css b/web/chat/chat-thread-list.css --- a/web/chat/chat-thread-list.css +++ b/web/chat/chat-thread-list.css @@ -15,9 +15,6 @@ top: -7px; left: 30px; } -.thread:first-child { - padding-top: 6px; -} .activeThread, .threadListSidebar:hover { @@ -265,6 +262,7 @@ display: flex; flex-direction: column; overflow: auto; + flex: 1; } div.createNewThread { diff --git a/web/chat/chat-thread-list.react.js b/web/chat/chat-thread-list.react.js --- a/web/chat/chat-thread-list.react.js +++ b/web/chat/chat-thread-list.react.js @@ -1,7 +1,10 @@ // @flow import invariant from 'invariant'; +import _sum from 'lodash/fp/sum.js'; import * as React from 'react'; +import AutoSizer from 'react-virtualized-auto-sizer'; +import { VariableSizeList } from 'react-window'; import { emptyItemText } from 'lib/shared/thread-utils.js'; @@ -14,6 +17,25 @@ import { useSelector } from '../redux/redux-utils.js'; import { useOnClickNewThread } from '../selectors/thread-selectors.js'; +const sizes = { + search: 68, + thread: 81, + sidebars: { sidebar: 32, seeMore: 22, spacer: 6 }, +}; + +const getThreadItemSize = item => { + const sidebarHeight = _sum(item.sidebars.map(s => sizes.sidebars[s.type])); + return sizes.thread + sidebarHeight; +}; + +const renderItem = ({ index, data, style }) => { + return ( +
+ {index === 0 ? data[0] : } +
+ ); +}; + function ChatThreadList(): React.Node { const threadListContext = React.useContext(ThreadListContext); invariant( @@ -33,31 +55,81 @@ const communityID = useSelector(state => state.communityPickerStore.chat); - const threadComponents: React.Node[] = React.useMemo(() => { - const threads = threadList - .filter( + const search = React.useMemo( + () => ( + + ), + [searchText, setSearchText], + ); + + const threadListContainerRef = React.useRef(); + + const threads = React.useMemo( + () => + threadList.filter( item => !communityID || item.threadInfo.community === communityID || item.threadInfo.id === communityID, - ) - .map(item => ); - if (threads.length === 0 && isBackground) { - threads.push(); + ), + [communityID, threadList], + ); + + React.useEffect(() => { + if (threadListContainerRef.current) { + threadListContainerRef.current.resetAfterIndex(0, false); + } + }, [threads]); + + const threadListContainer = React.useMemo(() => { + if (isBackground && threads.length === 0) { + return ( + <> + {search} + + + ); } - return threads; - }, [threadList, isBackground, communityID]); + + const items = [search, ...threads]; + + const itemKey = index => + index === 0 ? 'search' : items[index].threadInfo.id; + + const itemSize = index => { + if (index === 0) { + return sizes.search; + } + + return getThreadItemSize(items[index]); + }; + + return ( + + {({ height }) => ( + + {renderItem} + + )} + + ); + }, [isBackground, search, threads]); return ( <> -
- -
{threadComponents}
-
+
{threadListContainer}