diff --git a/web/chat/chat-message-list.css b/web/chat/chat-message-list.css --- a/web/chat/chat-message-list.css +++ b/web/chat/chat-message-list.css @@ -84,8 +84,14 @@ span.authorName { color: #777777; font-size: 14px; +} +span.authorNamePositionAvatar { padding: 4px 56px; } +span.authorNamePositionNoAvatar { + padding: 4px 24px; +} + div.darkTextMessage { color: white; } @@ -122,8 +128,14 @@ position: relative; display: flex; max-width: calc(min(68%, 1000px)); +} +div.messageBoxContainerPositionAvatar { margin: 0 4px; } +div.messageBoxContainerPositionNoAvatar { + margin: 0 4px 0 12px; +} + div.fixedWidthMessageBoxContainer { width: 68%; } diff --git a/web/chat/chat-thread-composer.react.js b/web/chat/chat-thread-composer.react.js --- a/web/chat/chat-thread-composer.react.js +++ b/web/chat/chat-thread-composer.react.js @@ -18,6 +18,7 @@ import type { InputState } from '../input/input-state.js'; import { updateNavInfoActionType } from '../redux/action-types.js'; import { useSelector } from '../redux/redux-utils.js'; +import { shouldRenderAvatars } from '../utils/avatar-utils.js'; type Props = { +userInfoInputArray: $ReadOnlyArray, @@ -85,6 +86,13 @@ [dispatch, userInfoInputArray], ); + const usernameStyle = React.useMemo( + () => ({ + marginLeft: shouldRenderAvatars ? 8 : 0, + }), + [], + ); + const userSearchResultList = React.useMemo(() => { if ( !userListItemsWithENSNames.length || @@ -103,7 +111,9 @@ >
-
{userSearchResult.username}
+
+ {userSearchResult.username} +
{userSearchResult.alertTitle}
@@ -117,6 +127,7 @@ userInfoInputArray.length, userListItemsWithENSNames, usernameInputText, + usernameStyle, ]); const hideSearch = React.useCallback( diff --git a/web/chat/chat-thread-list-item.react.js b/web/chat/chat-thread-list-item.react.js --- a/web/chat/chat-thread-list-item.react.js +++ b/web/chat/chat-thread-list-item.react.js @@ -23,6 +23,7 @@ useOnClickThread, useThreadIsActive, } from '../selectors/thread-selectors.js'; +import { shouldRenderAvatars } from '../utils/avatar-utils.js'; type Props = { +item: ChatThreadItem, @@ -83,6 +84,12 @@ unreadDot =
; } + const { color } = item.threadInfo; + const colorSplotchStyle = React.useMemo( + () => ({ backgroundColor: `#${color}` }), + [color], + ); + const sidebars = item.sidebars.map((sidebarItem, index) => { if (sidebarItem.type === 'sidebar') { const { type, ...sidebarInfo } = sidebarItem; @@ -124,13 +131,20 @@ const { uiName } = useResolvedThreadInfo(threadInfo); + const avatar = React.useMemo(() => { + if (!shouldRenderAvatars) { + return
; + } + return ; + }, [colorSplotchStyle, threadInfo]); + return ( <>
{unreadDot}
- + {avatar}
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 @@ -89,7 +89,8 @@ padding-top: 8px; } -div.spacer { +div.spacer, +div.colorSplotch { width: 42px; border-radius: 1.68px; } diff --git a/web/chat/composed-message.react.js b/web/chat/composed-message.react.js --- a/web/chat/composed-message.react.js +++ b/web/chat/composed-message.react.js @@ -18,6 +18,7 @@ import InlineEngagement from './inline-engagement.react.js'; import UserAvatar from '../components/user-avatar.react.js'; import { type InputState, InputStateContext } from '../input/input-state.js'; +import { shouldRenderAvatars } from '../utils/avatar-utils.js'; import { tooltipPositions, useMessageTooltip } from '../utils/tooltip-utils.js'; const availableTooltipPositionsForViewerMessage = [ @@ -80,6 +81,8 @@ const messageBoxContainerClassName = classNames({ [css.messageBoxContainer]: true, [css.fixedWidthMessageBoxContainer]: this.props.fixedWidth, + [css.messageBoxContainerPositionAvatar]: shouldRenderAvatars, + [css.messageBoxContainerPositionNoAvatar]: !shouldRenderAvatars, }); const messageBoxClassName = classNames({ [css.messageBox]: true, @@ -94,8 +97,13 @@ let authorName = null; const { stringForUser } = this.props; + const authorNameClassName = classNames({ + [css.authorName]: true, + [css.authorNamePositionAvatar]: shouldRenderAvatars, + [css.authorNamePositionNoAvatar]: !shouldRenderAvatars, + }); if (stringForUser) { - authorName = {stringForUser}; + authorName = {stringForUser}; } let deliveryIcon = null; @@ -143,13 +151,13 @@ } let avatar; - if (!isViewer && item.endsCluster) { + if (!isViewer && item.endsCluster && shouldRenderAvatars) { avatar = (
); - } else if (!isViewer) { + } else if (!isViewer && shouldRenderAvatars) { avatar =
; } diff --git a/web/chat/inline-engagement.css b/web/chat/inline-engagement.css --- a/web/chat/inline-engagement.css +++ b/web/chat/inline-engagement.css @@ -21,6 +21,11 @@ margin-left: 31px; } +div.leftContainerNoAvatar { + left: 12px; + margin-right: 12px; +} + a.threadsContainer, a.threadsSplitContainer, a.reactionsContainer, diff --git a/web/chat/inline-engagement.react.js b/web/chat/inline-engagement.react.js --- a/web/chat/inline-engagement.react.js +++ b/web/chat/inline-engagement.react.js @@ -13,6 +13,7 @@ import CommIcon from '../CommIcon.react.js'; import MessageReactionsModal from '../modals/chat/message-reactions-modal.react.js'; import { useOnClickThread } from '../selectors/thread-selectors.js'; +import { shouldRenderAvatars } from '../utils/avatar-utils.js'; type Props = { +threadInfo: ?ThreadInfo, @@ -31,6 +32,8 @@ [css.leftContainer]: positioning === 'left', [css.centerContainer]: positioning === 'center', [css.rightContainer]: positioning === 'right', + [css.leftContainerNoAvatar]: + positioning === 'left' && !shouldRenderAvatars, }, ]); diff --git a/web/chat/thread-top-bar.css b/web/chat/thread-top-bar.css --- a/web/chat/thread-top-bar.css +++ b/web/chat/thread-top-bar.css @@ -16,6 +16,13 @@ overflow: hidden; } +div.threadColorSquare { + width: 24px; + height: 24px; + border-radius: 4px; + flex: 0 0 auto; +} + .threadTitle { font-size: var(--m-font-16); font-weight: var(--bold); diff --git a/web/chat/thread-top-bar.react.js b/web/chat/thread-top-bar.react.js --- a/web/chat/thread-top-bar.react.js +++ b/web/chat/thread-top-bar.react.js @@ -9,12 +9,19 @@ import ThreadMenu from './thread-menu.react.js'; import css from './thread-top-bar.css'; import ThreadAvatar from '../components/thread-avatar.react.js'; +import { shouldRenderAvatars } from '../utils/avatar-utils.js'; type ThreadTopBarProps = { +threadInfo: ThreadInfo, }; function ThreadTopBar(props: ThreadTopBarProps): React.Node { const { threadInfo } = props; + const threadBackgroundColorStyle = React.useMemo( + () => ({ + background: `#${threadInfo.color}`, + }), + [threadInfo.color], + ); let threadMenu = null; if (!threadIsPending(threadInfo.id)) { @@ -23,10 +30,22 @@ const { uiName } = useResolvedThreadInfo(threadInfo); + const avatar = React.useMemo(() => { + if (!shouldRenderAvatars) { + return ( +
+ ); + } + return ; + }, [threadBackgroundColorStyle, threadInfo]); + return (
- + {avatar}
{uiName}
{threadMenu} diff --git a/web/chat/typeahead-tooltip.css b/web/chat/typeahead-tooltip.css --- a/web/chat/typeahead-tooltip.css +++ b/web/chat/typeahead-tooltip.css @@ -69,3 +69,7 @@ span.username { margin-left: 8px; } + +span.usernameNoAvatar { + margin-left: 0; +} diff --git a/web/components/avatar.react.js b/web/components/avatar.react.js --- a/web/components/avatar.react.js +++ b/web/components/avatar.react.js @@ -6,6 +6,7 @@ import type { ResolvedClientAvatar } from 'lib/types/avatar-types'; import css from './avatar.css'; +import { shouldRenderAvatars } from '../utils/avatar-utils.js'; type Props = { +avatarInfo: ResolvedClientAvatar, @@ -61,7 +62,7 @@ emojiSizeClassName, ]); - return avatar; + return shouldRenderAvatars ? avatar : null; } export default Avatar; diff --git a/web/modals/chat/message-reactions-modal.react.js b/web/modals/chat/message-reactions-modal.react.js --- a/web/modals/chat/message-reactions-modal.react.js +++ b/web/modals/chat/message-reactions-modal.react.js @@ -7,6 +7,7 @@ import css from './message-reactions-modal.css'; import UserAvatar from '../../components/user-avatar.react.js'; +import { shouldRenderAvatars } from '../../utils/avatar-utils.js'; import Modal from '../modal.react.js'; type Props = { @@ -19,18 +20,27 @@ const messageReactionsList = useMessageReactionsList(reactions); + const usernameStyle = React.useMemo( + () => ({ + marginLeft: shouldRenderAvatars ? 8 : 0, + }), + [], + ); + const reactionsList = React.useMemo( () => messageReactionsList.map(messageReactionUser => (
-
{messageReactionUser.username}
+
+ {messageReactionUser.username} +
{messageReactionUser.reaction}
)), - [messageReactionsList], + [messageReactionsList, usernameStyle], ); return ( diff --git a/web/modals/components/add-members-item.react.js b/web/modals/components/add-members-item.react.js --- a/web/modals/components/add-members-item.react.js +++ b/web/modals/components/add-members-item.react.js @@ -7,6 +7,7 @@ import css from './add-members.css'; import Button from '../../components/button.react.js'; import UserAvatar from '../../components/user-avatar.react.js'; +import { shouldRenderAvatars } from '../../utils/avatar-utils.js'; type AddMembersItemProps = { +userInfo: UserListItem, @@ -37,6 +38,13 @@ } }, [canBeAdded, userAdded, userInfo.alertTitle]); + const usernameStyle = React.useMemo( + () => ({ + marginLeft: shouldRenderAvatars ? 8 : 0, + }), + [], + ); + return ( diff --git a/web/modals/threads/sidebars/sidebar.react.js b/web/modals/threads/sidebars/sidebar.react.js --- a/web/modals/threads/sidebars/sidebar.react.js +++ b/web/modals/threads/sidebars/sidebar.react.js @@ -14,6 +14,7 @@ import ThreadAvatar from '../../../components/thread-avatar.react.js'; import { getDefaultTextMessageRules } from '../../../markdown/rules.react.js'; import { useOnClickThread } from '../../../selectors/thread-selectors.js'; +import { shouldRenderAvatars } from '../../../utils/avatar-utils.js'; type Props = { +sidebar: ChatThreadItem, @@ -44,7 +45,7 @@ const previewTextClassName = classNames({ [css.longTextEllipsis]: true, - [css.avatarOffset]: true, + [css.avatarOffset]: shouldRenderAvatars, }); const lastActivity = React.useMemo( diff --git a/web/modals/threads/subchannels/subchannel.react.js b/web/modals/threads/subchannels/subchannel.react.js --- a/web/modals/threads/subchannels/subchannel.react.js +++ b/web/modals/threads/subchannels/subchannel.react.js @@ -4,6 +4,7 @@ import * as React from 'react'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; import { type ChatThreadItem } from 'lib/selectors/chat-selectors.js'; import { useMessagePreview } from 'lib/shared/message-utils.js'; import { shortAbsoluteDate } from 'lib/utils/date-utils.js'; @@ -14,6 +15,7 @@ import ThreadAvatar from '../../../components/thread-avatar.react.js'; import { getDefaultTextMessageRules } from '../../../markdown/rules.react.js'; import { useOnClickThread } from '../../../selectors/thread-selectors.js'; +import { shouldRenderAvatars } from '../../../utils/avatar-utils.js'; type Props = { +chatThreadItem: ChatThreadItem, @@ -75,9 +77,16 @@ const { uiName } = useResolvedThreadInfo(threadInfo); + const avatar = React.useMemo(() => { + if (!shouldRenderAvatars) { + return ; + } + return ; + }, [threadInfo]); + return (
diff --git a/web/navigation-panels/nav-state-info-bar.css b/web/navigation-panels/nav-state-info-bar.css --- a/web/navigation-panels/nav-state-info-bar.css +++ b/web/navigation-panels/nav-state-info-bar.css @@ -7,6 +7,14 @@ overflow: hidden; } +div.threadColorSquare { + width: 24px; + height: 24px; + border-radius: 4px; + flex: 0 0 auto; + margin: 0 12px 0 16px; +} + div.avatarContainer { margin: 0 12px 0 16px; } diff --git a/web/navigation-panels/nav-state-info-bar.react.js b/web/navigation-panels/nav-state-info-bar.react.js --- a/web/navigation-panels/nav-state-info-bar.react.js +++ b/web/navigation-panels/nav-state-info-bar.react.js @@ -8,6 +8,7 @@ import ThreadAncestors from './chat-thread-ancestors.react.js'; import css from './nav-state-info-bar.css'; import ThreadAvatar from '../components/thread-avatar.react.js'; +import { shouldRenderAvatars } from '../utils/avatar-utils.js'; type NavStateInfoBarProps = { +threadInfo: ThreadInfo, @@ -15,11 +16,32 @@ function NavStateInfoBar(props: NavStateInfoBarProps): React.Node { const { threadInfo } = props; - return ( - <> + const threadBackgroundColorStyle = React.useMemo( + () => ({ + background: `#${threadInfo.color}`, + }), + [threadInfo.color], + ); + + const avatar = React.useMemo(() => { + if (!shouldRenderAvatars) { + return ( +
+ ); + } + return (
+ ); + }, [threadBackgroundColorStyle, threadInfo]); + + return ( + <> + {avatar} ); diff --git a/web/settings/account-settings.react.js b/web/settings/account-settings.react.js --- a/web/settings/account-settings.react.js +++ b/web/settings/account-settings.react.js @@ -20,6 +20,7 @@ import Button from '../components/button.react.js'; import UserAvatar from '../components/user-avatar.react.js'; import { useSelector } from '../redux/redux-utils.js'; +import { shouldRenderAvatars } from '../utils/avatar-utils.js'; function AccountSettings(): React.Node { const sendLogoutRequest = useServerCall(logOut); @@ -57,6 +58,13 @@ const currentUserInfo = useSelector(state => state.currentUserInfo); const stringForUser = useStringForUser(currentUserInfo); + const contentStyle = React.useMemo( + () => ({ + marginTop: shouldRenderAvatars ? 32 : 0, + }), + [], + ); + if (!currentUserInfo || currentUserInfo.anonymous) { return null; } @@ -80,7 +88,7 @@

My Account

-
+