diff --git a/web/assets.js b/web/assets.js
new file mode 100644
index 000000000..976edd48e
--- /dev/null
+++ b/web/assets.js
@@ -0,0 +1,8 @@
+// @flow
+
+export const assetCacheURLPrefix = 'https://dh9fld3hutpxf.cloudfront.net';
+
+// Background Illustration
+export const backgroundIllustrationFileName = 'background-illustration.svg';
+export const backgroundIllustrationHeight = '100px';
+export const backgroundIllustrationWidth = '133px';
diff --git a/web/chat/chat-thread-list.css b/web/chat/chat-thread-list.css
index fd984319b..ce8a403e8 100644
--- a/web/chat/chat-thread-list.css
+++ b/web/chat/chat-thread-list.css
@@ -1,308 +1,314 @@
div.thread {
display: flex;
flex-direction: row;
}
div.threadListSidebar {
display: flex;
flex-direction: row;
height: 32px;
padding-right: 8px;
position: relative;
cursor: pointer;
}
div.threadListSidebar > svg {
position: absolute;
top: -7px;
left: 30px;
}
div.thread:first-child {
padding-top: 6px;
}
div.activeThread,
div.threadListSidebar:hover {
background: var(--thread-active-bg);
}
div.activeThread :is(div.dark, .lastMessage span.read, .title) {
color: var(--chat-thread-list-color-active);
}
div.activeThread .lastMessage.read {
color: var(--chat-thread-list-color-active);
}
div.activeThread.thread:hover {
background: var(--thread-active-bg);
}
div.thread:hover {
background: var(--thread-hover-bg);
}
div.title {
flex: 1;
font-size: var(--m-font-16);
font-weight: var(--semi-bold);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--thread-color-read);
line-height: var(--line-height-text);
}
div.threadArrowExtender {
width: 10px;
position: absolute;
border-left: 0.5px solid var(--arrow-extension-color);
height: 8px;
top: -15px;
left: 32px;
}
.threadButton {
flex: 1;
cursor: pointer;
overflow: hidden;
padding-left: 12px;
}
.threadButton + div {
display: flex;
flex-direction: column;
}
.threadButtonSidebar {
flex: 1;
cursor: pointer;
overflow: hidden;
display: flex;
align-items: center;
padding-left: 8px;
}
p.breadCrumbs {
display: flex;
padding: 8px 0 2px 0;
font-size: var(--xs-font-12);
font-weight: var(--normal);
color: var(--breadcrumb-color);
}
p.breadCrumbs.unread {
color: var(--breadcrumb-color-unread);
}
span.breadCrumb {
display: flex;
align-items: center;
white-space: nowrap;
text-overflow: ellipsis;
}
div.colorContainer {
display: flex;
padding-top: 8px;
}
div.spacer,
div.colorSplotch {
width: 42px;
border-radius: 1.68px;
}
div.colorSplotchContainer {
height: 42px;
display: flex;
}
div.lastActivity {
font-size: var(--xxs-font-10);
color: var(--fg);
line-height: 1.5;
padding-right: 16px;
font-weight: var(--semi-bold);
white-space: nowrap;
flex-grow: 1;
padding-bottom: 12px;
align-items: flex-end;
display: flex;
}
div.lastMessage {
font-size: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: var(--line-height-text);
padding-bottom: 8px;
}
div.threadRow > .lastMessage {
color: var(--thread-last-message-color-read);
font-size: var(--s-font-14);
}
div.unread {
color: var(--fg);
font-weight: var(--semi-bold);
}
div.lastMessage.unread {
color: var(--fg);
}
div.dark {
color: var(--thread-color-read);
padding-right: 16px;
}
.read {
color: var(--thread-from-color-read);
}
div.dotContainer {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
}
div.unreadDot {
height: 4px;
width: 4px;
background: var(--fg);
border-radius: 15px;
align-self: center;
}
div.italic {
font-style: italic;
}
div.sidebarTitle {
flex: 1;
font-size: var(--s-font-14);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--thread-color-read);
align-self: flex-start;
}
div.threadListSidebar > div.dotContainer {
width: 16px;
}
div.sidebarTitle.unread {
color: var(--fg);
}
div.seeMoreButton {
padding-left: 66px;
}
div.sidebarLastActivity {
white-space: nowrap;
font-size: var(--xxs-font-10);
line-height: var(--line-height-text);
font-weight: var(--semi-bold);
}
svg.sidebarIcon {
color: var(--thread-color-read);
padding: 0 6px;
font-size: 20px;
}
div.sidebar .menu > button svg {
font-size: 16px;
color: var(--thread-color-read);
}
div.sidebar .menu {
opacity: 0;
}
div.sidebar:hover .menu {
display: flex;
align-self: flex-end;
opacity: 1;
}
.menu {
position: relative;
display: flex;
justify-content: flex-end;
}
.menu > button {
background-color: transparent;
color: var(--thread-color-read);
border: none;
cursor: pointer;
display: flex;
align-items: center;
}
.menu > button:focus {
outline: none;
}
.menuContent {
display: none;
position: absolute;
top: calc(100% + 1px);
right: 0;
z-index: 1;
width: max-content;
overflow: hidden;
background-color: #eeeeee;
border-radius: 5px;
box-shadow: 1px 1px 5px 2px #00000022;
}
.menuContentVisible {
display: block;
}
button.menuContent {
border: none;
cursor: pointer;
padding: 10px;
font-size: 16px;
}
button.menuContent:hover {
background-color: #dddddd;
}
ul.list {
margin: 5px 3px 10px 0px;
overflow: auto;
}
div.search {
display: flex;
background-color: #dddddd;
border-radius: 5px;
padding: 3px 5px;
align-items: center;
}
svg.searchVector {
fill: #aaaaaa;
height: 22px;
width: 22px;
padding: 0 3px;
margin-left: 8px;
}
div.search > input {
color: black;
padding: 0;
border: none;
background-color: #dddddd;
font-weight: 600;
font-size: 15px;
flex-grow: 1;
margin-left: 3px;
}
div.search > input:focus {
outline: none;
}
svg.clearQuery {
font-size: 15px;
padding-bottom: 1px;
padding-right: 2px;
color: #aaaaaa;
}
svg.clearQuery:hover {
font-size: 15px;
padding-bottom: 1px;
padding-right: 2px;
color: white;
}
div.spacer {
height: 6px;
}
-div.emptyItem {
- padding: 10px;
+div.emptyItemContainer {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+div.emptyItemText {
+ padding: 16px;
font-size: 16px;
text-align: center;
white-space: pre-wrap;
color: var(--fg);
}
div.threadListContainer {
display: flex;
flex-direction: column;
}
diff --git a/web/chat/chat-thread-list.react.js b/web/chat/chat-thread-list.react.js
index dda220a3f..33954d862 100644
--- a/web/chat/chat-thread-list.react.js
+++ b/web/chat/chat-thread-list.react.js
@@ -1,53 +1,68 @@
// @flow
import invariant from 'invariant';
import * as React from 'react';
import { emptyItemText } from 'lib/shared/thread-utils';
+import {
+ assetCacheURLPrefix,
+ backgroundIllustrationFileName,
+ backgroundIllustrationHeight,
+ backgroundIllustrationWidth,
+} from '../assets';
import Search from '../components/search.react';
import ChatThreadListItem from './chat-thread-list-item.react';
import css from './chat-thread-list.css';
import { ThreadListContext } from './thread-list-provider';
function ChatThreadList(): React.Node {
const threadListContext = React.useContext(ThreadListContext);
invariant(
threadListContext,
'threadListContext should be set in ChatThreadList',
);
const {
activeTab,
threadList,
setSearchText,
searchText,
} = threadListContext;
const isBackground = activeTab === 'Background';
const threadComponents: React.Node[] = React.useMemo(() => {
const threads = threadList.map(item => (