Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3525995
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
View Options
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(
() => (
- <Search
- onChangeText={setSearchText}
- searchText={searchText}
- placeholder="Search chats"
- />
+ <div className={css.searchBarContainer}>
+ <Search
+ onChangeText={setSearchText}
+ searchText={searchText}
+ placeholder="Search chats"
+ />
+ </div>
),
[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<HTMLInputElement>) => {
if (event.key === 'Enter') {
onPressSearch();
}
},
[onPressSearch],
);
const modifiedItems = useParseSearchResults(
threadInfo,
getSearchResults(threadInfo.id),
);
const { clearTooltip } = useTooltipContext();
const messageContainer = React.useRef<?HTMLDivElement>(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) => (
<MessageResult
key={item.messageInfo.id}
item={item}
threadInfo={threadInfo}
scrollable={false}
/>
),
[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 (
<div className={css.footer}>Your search results will appear here</div>
);
}
if (!endReached) {
return (
<div key="search-loader" className={css.loading}>
<LoadingIndicator status="loading" size="medium" color="white" />
</div>
);
}
if (modifiedItems.length > 0) {
return <div className={css.footer}>End of results</div>;
}
return (
<div className={css.footer}>
No results. Please try using different keywords to refine your search
</div>
);
}, [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 (
<Modal name="Search messages" onClose={popModal} size="large">
<div className={css.container}>
<div className={css.header}>
- <Search
- onChangeText={setInput}
- searchText={input}
- placeholder={searchPlaceholder}
- onClearText={clearQueryWrapper}
- onKeyDown={onKeyDown}
- />
+ <div className={css.searchBarContainer}>
+ <Search
+ onChangeText={setInput}
+ searchText={input}
+ placeholder={searchPlaceholder}
+ onClearText={clearQueryWrapper}
+ onKeyDown={onKeyDown}
+ />
+ </div>
<Button
onClick={onPressSearch}
variant="filled"
className={css.button}
>
Search
</Button>
</div>
<div className={css.content} ref={messageContainer} onScroll={onScroll}>
{messages}
{footer}
</div>
</div>
</Modal>
);
}
export default MessageSearchModal;
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Dec 25, 7:06 PM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2700855
Default Alt Text
(15 KB)
Attached To
Mode
rCOMM Comm
Attached
Detach File
Event Timeline
Log In to Comment