diff --git a/web/chat/chat-thread-composer.css b/web/chat/chat-thread-composer.css
index 0c542b5f2..4fdfc82d0 100644
--- a/web/chat/chat-thread-composer.css
+++ b/web/chat/chat-thread-composer.css
@@ -1,78 +1,79 @@
div.threadSearchContainer {
background-color: var(--thread-creation-search-container-bg);
color: var(--fg);
display: flex;
flex-direction: column;
max-height: 50%;
overflow: auto;
flex-shrink: 0;
}
div.fullHeight {
flex-grow: 1;
max-height: 100%;
}
div.userSelectedTags {
display: flex;
flex-wrap: wrap;
flex-direction: row;
align-items: center;
gap: 4px;
padding: 4px 12px;
margin-bottom: 8px;
}
div.searchRow {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 8px;
}
div.searchField {
flex-grow: 1;
+ padding: 1rem;
}
.closeSearch {
color: var(--thread-creation-close-search-color);
margin: 0 8px;
}
ul.searchResultsContainer {
display: flex;
flex-direction: column;
overflow: auto;
padding: 0 12px 8px;
list-style-type: none;
}
.searchResultsItem {
display: flex;
}
.searchResultsItem:hover {
background-color: var(--thread-creation-search-item-bg-hover);
}
.searchResultsButton {
justify-content: space-between;
flex: 1;
padding: 8px 12px;
}
div.userName {
color: var(--fg);
margin-left: 8px;
}
div.userInfo {
font-style: italic;
color: var(--thread-creation-search-item-info-color);
}
div.userContainer {
display: flex;
flex-direction: row;
align-items: center;
}
diff --git a/web/chat/chat-thread-list-search.react.js b/web/chat/chat-thread-list-search.react.js
index 07639a903..3e18677a0 100644
--- a/web/chat/chat-thread-list-search.react.js
+++ b/web/chat/chat-thread-list-search.react.js
@@ -1,29 +1,32 @@
// @flow
import invariant from 'invariant';
import * as React from 'react';
+import css from './chat-thread-list.css';
import { ThreadListContext } from './thread-list-provider.js';
import Search from '../components/search.react.js';
function ChatThreadListSearch(): React.Node {
const threadListContext = React.useContext(ThreadListContext);
invariant(
threadListContext,
'threadListContext should be set in ChatThreadListSearch',
);
const { setSearchText, searchText } = threadListContext;
return React.useMemo(
() => (
-
+
+
+
),
[searchText, setSearchText],
);
}
export default ChatThreadListSearch;
diff --git a/web/chat/chat-thread-list.css b/web/chat/chat-thread-list.css
index e522ea717..323c879b6 100644
--- a/web/chat/chat-thread-list.css
+++ b/web/chat/chat-thread-list.css
@@ -1,282 +1,286 @@
.thread {
display: flex;
flex-direction: row;
}
.sidebarItem {
display: flex;
flex-direction: row;
width: 100%;
}
.threadListSidebar {
display: flex;
flex-direction: row;
height: 32px;
padding-right: 8px;
position: relative;
cursor: pointer;
}
.threadListSidebar > svg {
position: absolute;
top: -7px;
left: 30px;
}
.activeThread,
.threadListSidebar:hover {
background: var(--thread-active-bg);
}
.activeThread :is(.title, .lastMessage, .lastMessage *) {
color: var(--chat-thread-list-color-active);
}
.activeThread.thread:hover {
background: var(--thread-active-bg);
}
.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);
}
.threadButton {
flex: 1;
cursor: pointer;
overflow: hidden;
padding-left: 12px;
}
.threadButton + div {
display: flex;
flex-direction: column;
}
.threadButtonSidebar {
cursor: pointer;
overflow: hidden;
display: flex;
align-items: center;
padding-left: 12px;
}
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;
}
span.breadCrumb svg {
margin-left: 4px;
margin-right: 4px;
}
div.colorContainer {
display: flex;
padding-top: 8px;
}
div.spacer {
width: 42px;
border-radius: 1.68px;
}
div.avatarContainer {
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: var(--s-font-14);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: var(--line-height-text);
padding-bottom: 8px;
}
div.unread {
color: var(--fg);
font-weight: var(--semi-bold);
}
div.dark {
color: var(--thread-color-read);
padding-right: 16px;
}
.messagePreviewPrimary {
color: var(--thread-color-read);
}
.messagePreviewSecondary {
color: var(--thread-preview-secondary);
}
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;
}
.threadListSidebar > div.dotContainer {
width: 16px;
}
div.sidebarTitle.unread {
color: var(--fg);
}
div.seeMoreButton {
display: flex;
align-items: center;
padding-left: 22px;
}
div.seeMoreText {
padding-left: 14px;
}
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 0;
overflow: auto;
}
div.spacer {
height: 6px;
}
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;
overflow: hidden;
flex: 1;
}
div.createNewThread {
display: flex;
flex-direction: column;
align-items: stretch;
padding: 8px;
}
img.longArrow {
height: 40px;
width: 25px;
position: absolute;
left: 28.5px;
top: -18px;
}
img.arrow {
position: absolute;
left: 28px;
top: -10px;
}
+
+.searchBarContainer {
+ padding: 1rem;
+}
diff --git a/web/components/search.css b/web/components/search.css
index 1303f25f8..725f2fd74 100644
--- a/web/components/search.css
+++ b/web/components/search.css
@@ -1,42 +1,41 @@
div.searchContainer {
background-color: var(--inputField-background-secondary-default);
display: flex;
align-items: center;
- margin: 1rem;
border-radius: 8px;
padding: 8px;
flex: 1;
}
div.searchIcon {
display: flex;
color: var(--inputField-label-secondary-default);
}
input.searchInput,
#searchInputID {
background-color: transparent;
font-size: var(--m-font-16);
line-height: 1.5;
padding: 4px 12px;
flex: 1;
border: none;
color: var(--inputField-label-primary-default);
outline: none;
}
input.searchInput::placeholder {
color: var(--inputField-label-secondary-default);
}
button.clearSearch {
color: var(--inputField-clearIcon-primary-default);
transition: ease-in-out 0.15s;
background: var(--inputField-clearBackground-primary-default);
border-radius: 50%;
padding: 6px;
}
button.clearSearchDisabled {
opacity: 0;
}
diff --git a/web/modals/search/message-search-modal.css b/web/modals/search/message-search-modal.css
index 43c7a588d..10c3d15cd 100644
--- a/web/modals/search/message-search-modal.css
+++ b/web/modals/search/message-search-modal.css
@@ -1,40 +1,45 @@
.container {
display: flex;
flex-direction: column;
overflow: hidden;
height: 80vh;
}
.content {
overflow-y: scroll;
border-top: 2px solid var(--border-color);
padding: 16px 0;
}
.content > * {
margin-bottom: 16px;
}
.loading {
text-align: center;
margin-bottom: 8px;
margin-top: 24px;
}
.footer {
color: var(--modal-secondary-label);
size: 14;
font-weight: 400;
text-align: center;
margin-top: 20px;
}
.header {
display: flex;
flex-direction: row;
margin-bottom: 16px;
}
.button {
margin: 10px 10px 10px 0;
}
+
+.searchBarContainer {
+ padding: 1rem;
+ flex-grow: 1;
+}
diff --git a/web/modals/search/message-search-modal.react.js b/web/modals/search/message-search-modal.react.js
index 7de301111..47c5a7d7c 100644
--- a/web/modals/search/message-search-modal.react.js
+++ b/web/modals/search/message-search-modal.react.js
@@ -1,159 +1,161 @@
// @flow
import * as React from 'react';
import { useModalContext } from 'lib/components/modal-provider.react.js';
import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js';
import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js';
import css from './message-search-modal.css';
import { useParseSearchResults } from './message-search-utils.react.js';
import Button from '../../components/button.react.js';
import MessageResult from '../../components/message-result.react.js';
import Search from '../../components/search.react.js';
import LoadingIndicator from '../../loading-indicator.react.js';
import { useMessageSearchContext } from '../../search/message-search-state-provider.react.js';
import { useTooltipContext } from '../../tooltips/tooltip-provider.js';
import Modal from '../modal.react.js';
type ContentProps = {
+threadInfo: ThreadInfo,
};
function MessageSearchModal(props: ContentProps): React.Node {
const { threadInfo } = props;
const {
getQuery,
setQuery,
clearQuery,
searchMessages,
getSearchResults,
getEndReached,
} = useMessageSearchContext();
const [input, setInput] = React.useState(getQuery(threadInfo.id));
const onPressSearch = React.useCallback(() => {
setQuery(input, threadInfo.id);
searchMessages(threadInfo.id);
}, [setQuery, input, searchMessages, threadInfo.id]);
const onKeyDown = React.useCallback(
(event: SyntheticKeyboardEvent) => {
if (event.key === 'Enter') {
onPressSearch();
}
},
[onPressSearch],
);
const modifiedItems = useParseSearchResults(
threadInfo,
getSearchResults(threadInfo.id),
);
const { clearTooltip } = useTooltipContext();
const messageContainer = React.useRef(null);
const possiblyLoadMoreMessages = React.useCallback(() => {
if (!messageContainer.current) {
return;
}
const loaderTopOffset = 32;
const { scrollTop, scrollHeight, clientHeight } = messageContainer.current;
if (Math.abs(scrollTop) + clientHeight + loaderTopOffset < scrollHeight) {
return;
}
searchMessages(threadInfo.id);
}, [searchMessages, threadInfo.id]);
const onScroll = React.useCallback(() => {
clearTooltip();
possiblyLoadMoreMessages();
}, [clearTooltip, possiblyLoadMoreMessages]);
const renderItem = React.useCallback(
(item: ChatMessageInfoItem) => (
),
[threadInfo],
);
const messages = React.useMemo(
() => modifiedItems.map(item => renderItem(item)),
[modifiedItems, renderItem],
);
const endReached = getEndReached(threadInfo.id);
const query = getQuery(threadInfo.id);
const footer = React.useMemo(() => {
if (query === '') {
return (
Your search results will appear here
);
}
if (!endReached) {
return (
);
}
if (modifiedItems.length > 0) {
return End of results
;
}
return (
No results. Please try using different keywords to refine your search
);
}, [query, endReached, modifiedItems.length]);
const { uiName } = useResolvedThreadInfo(threadInfo);
const searchPlaceholder = `Searching in ${uiName}`;
const { popModal } = useModalContext();
const clearQueryWrapper = React.useCallback(
() => clearQuery(threadInfo.id),
[clearQuery, threadInfo.id],
);
return (
);
}
export default MessageSearchModal;