feat(app): restyle the inbox and message preview surfaces (#1706)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-18 00:43:18 +02:00
1 parent 41c7acdd8f
commit cc105883a5
55 files changed
+10669 -10576

No files matched your search

@@ -258,7 +258,6 @@ export type MessageBehaviorOverrides = Partial<{
mobileLayoutEnabled: boolean;
messageGroupSpacing: number;
messageDisplayCompact: boolean;
prefersReducedMotion: boolean;
isEditing: boolean;
isReplying: boolean;
isHighlight: boolean;
@@ -285,7 +284,7 @@ interface MessageProps {
behaviorOverrides?: MessageBehaviorOverrides;
compact?: boolean;
idPrefix?: string;
readonlyPreview?: boolean;
suppressMessageActions?: boolean;
onHeadingActivate?: () => void;
}
@@ -304,7 +303,7 @@ export const Message: React.FC<MessageProps> = observer((props) => {
behaviorOverrides,
compact,
idPrefix = 'message',
readonlyPreview,
suppressMessageActions,
onHeadingActivate,
} = props;
const {i18n} = useLingui();
@@ -326,7 +325,7 @@ export const Message: React.FC<MessageProps> = observer((props) => {
const mobileLayoutEnabled = behaviorOverrides?.mobileLayoutEnabled ?? MobileLayout.isEnabled();
const messageDisplayCompact =
compact ?? behaviorOverrides?.messageDisplayCompact ?? UserSettings.getMessageDisplayCompact();
const prefersReducedMotion = behaviorOverrides?.prefersReducedMotion ?? Accessibility.useReducedMotion;
const prefersReducedMotion = Accessibility.useReducedMotion;
const isEditing = behaviorOverrides?.isEditing ?? MessageEdit.isEditing(message.channelId, message.id);
const isReplying = behaviorOverrides?.isReplying ?? MessageReply.isReplying(message.channelId, message.id);
const isHighlight = behaviorOverrides?.isHighlight ?? MessageReply.isHighlight(message.id);
@@ -742,7 +741,7 @@ export const Message: React.FC<MessageProps> = observer((props) => {
}
: undefined,
onPopoutToggle: handleMessagePopoutToggle,
readonlyPreview,
suppressMessageActions,
onHeadingActivate,
}),
[
@@ -756,7 +755,7 @@ export const Message: React.FC<MessageProps> = observer((props) => {
previewOverrides,
previewMode,
handleMessagePopoutToggle,
readonlyPreview,
suppressMessageActions,
onHeadingActivate,
],
);
@@ -780,8 +779,9 @@ export const Message: React.FC<MessageProps> = observer((props) => {
astNodes.length === 1 &&
astNodes[0].type === NodeType.Link &&
!message.suppressEmbeds;
const shouldDisableHoverBackground = (prefersReducedMotion && !isEditing) || readonlyPreview;
const shouldDisableHoverBackground = prefersReducedMotion && !isEditing;
const isKeyboardFocused = keyboardModeEnabled && isFocusedWithin;
const isPreview = previewContext != null;
const shouldApplySpacing = !shouldGroup && !removeTopSpacing && previewContext !== MessagePreviewContext.LIST_POPOUT;
const systemFollowsSystem = Boolean(
shouldGroup && prevMessage && isDisplaySystemMessage(prevMessage) && isDisplaySystemMessage(message),
@@ -790,7 +790,7 @@ export const Message: React.FC<MessageProps> = observer((props) => {
() =>
clsx(
messageDisplayCompact ? styles.messageCompact : styles.message,
isHovering && styles.messageHovered,
isHovering && !isPreview && styles.messageHovered,
shouldDisableHoverBackground && styles.messageNoHover,
isEditing && styles.messageEditing,
!messageDisplayCompact &&
@@ -812,8 +812,8 @@ export const Message: React.FC<MessageProps> = observer((props) => {
!isEditing &&
message.isUserMessage() &&
styles.messageNoText,
isKeyboardFocused && styles.keyboardFocused,
isKeyboardFocused && 'keyboard-focus-active',
isKeyboardFocused && !isPreview && styles.keyboardFocused,
isKeyboardFocused && !isPreview && 'keyboard-focus-active',
shouldApplySpacing && previewContext && styles.messagePreviewSpacing,
),
[
@@ -836,16 +836,17 @@ export const Message: React.FC<MessageProps> = observer((props) => {
shouldHideContent,
isKeyboardFocused,
shouldApplySpacing,
isPreview,
],
);
const shouldShowActionBar = useMemo(
() =>
!previewContext &&
!readonlyPreview &&
!suppressMessageActions &&
message.state !== MessageStates.SENDING &&
!isEditing &&
!mobileLayoutEnabled,
[previewContext, readonlyPreview, message.state, isEditing, mobileLayoutEnabled],
[previewContext, suppressMessageActions, message.state, isEditing, mobileLayoutEnabled],
);
const shouldRenderInlineActionBar = useMemo(
() => shouldShowActionBar && (previewMode || isHovering || isKeyboardFocused || contextMenuOpen || isPopoutOpen),
@@ -11,6 +11,7 @@ import type {ChannelMessages} from '@app/features/messaging/state/ChannelMessage
import {type ChannelStreamItem, ChannelStreamType} from '@app/features/messaging/utils/MessageGroupingUtils';
import {IS_DEV} from '@app/features/platform/types/Env';
import {Logger} from '@app/features/platform/utils/AppLogger';
import type {MessagePreviewContext} from '@fluxer/constants/src/ChannelConstants';
import {MessageTypes} from '@fluxer/constants/src/ChannelConstants';
import type React from 'react';
@@ -39,7 +40,8 @@ interface RenderChannelStreamProps {
messageRowClassName?: string;
messageActionsClassName?: string;
renderMessageActions?: (message: Message) => React.ReactNode;
readonlyPreview?: boolean;
suppressMessageActions?: boolean;
previewContext?: keyof typeof MessagePreviewContext;
dateDividerClassName?: string;
suppressUnreadIndicator?: boolean;
getMessageHeadingActivate?: (message: Message) => (() => void) | undefined;
@@ -58,7 +60,8 @@ export function renderChannelStream(props: RenderChannelStreamProps): Array<Reac
messageRowClassName,
messageActionsClassName,
renderMessageActions,
readonlyPreview,
suppressMessageActions,
previewContext,
dateDividerClassName,
suppressUnreadIndicator,
getMessageHeadingActivate,
@@ -129,7 +132,8 @@ export function renderChannelStream(props: RenderChannelStreamProps): Array<Reac
messageRowClassName={messageRowClassName}
messageActionsClassName={messageActionsClassName}
renderMessageActions={renderMessageActions}
readonlyPreview={readonlyPreview}
suppressMessageActions={suppressMessageActions}
previewContext={previewContext}
getMessageHeadingActivate={getMessageHeadingActivate}
data-flx="channel.channel-message-stream.flush-pending-group.message-group"
/>,
@@ -574,9 +574,10 @@ const StickerItem = observer(
},
);
export const MessageAttachments = observer(() => {
const {channel, message, handleDelete, previewContext, onPopoutToggle, readonlyPreview} = useMessageViewContext();
const {channel, message, handleDelete, previewContext, onPopoutToggle, suppressMessageActions} =
useMessageViewContext();
const isPreview = Boolean(previewContext);
const reactionsIsPreview = isPreview || Boolean(readonlyPreview);
const reactionsIsPreview = isPreview || Boolean(suppressMessageActions);
const reactions = useMessageReactionsSnapshot(message.id);
const {shouldAnimate, interactionHandlers} = useStickerAnimation();
const spoileredUrlEmbeds = useMemo(() => {
@@ -40,7 +40,7 @@ export interface MessageGroupProps {
messageRowClassName?: string;
messageActionsClassName?: string;
renderMessageActions?: (message: Message) => React.ReactNode;
readonlyPreview?: boolean;
suppressMessageActions?: boolean;
previewContext?: keyof typeof MessagePreviewContext;
behaviorOverrides?: MessageBehaviorOverrides;
renderMessageWrapper?: (props: MessageGroupRenderWrapperProps) => React.ReactNode;
@@ -61,7 +61,7 @@ export const MessageGroup: React.FC<MessageGroupProps> = observer((props) => {
messageRowClassName,
messageActionsClassName,
renderMessageActions,
readonlyPreview,
suppressMessageActions,
previewContext,
behaviorOverrides: providedBehaviorOverrides,
renderMessageWrapper,
@@ -70,14 +70,13 @@ export const MessageGroup: React.FC<MessageGroupProps> = observer((props) => {
const groupId = useMemo(() => messages[0]?.id, [messages]);
const behaviorOverrides = useMemo(
() =>
readonlyPreview
suppressMessageActions
? {
...providedBehaviorOverrides,
disableContextMenu: true,
prefersReducedMotion: true,
}
: providedBehaviorOverrides,
[readonlyPreview, providedBehaviorOverrides],
[suppressMessageActions, providedBehaviorOverrides],
);
const renderedMessages = useMemo(
() =>
@@ -96,7 +95,7 @@ export const MessageGroup: React.FC<MessageGroupProps> = observer((props) => {
compact={messageDisplayCompact}
idPrefix={idPrefix}
behaviorOverrides={behaviorOverrides}
readonlyPreview={readonlyPreview}
suppressMessageActions={suppressMessageActions}
previewContext={previewContext}
onHeadingActivate={getMessageHeadingActivate?.(message)}
data-flx="channel.message-group.rendered-messages.message-component"
@@ -151,7 +150,7 @@ export const MessageGroup: React.FC<MessageGroupProps> = observer((props) => {
messageActionsClassName,
renderMessageActions,
behaviorOverrides,
readonlyPreview,
suppressMessageActions,
previewContext,
renderMessageWrapper,
getMessageHeadingActivate,
@@ -34,7 +34,7 @@ export interface MessageViewContextValue {
previewPermissions?: MessagePreviewPermissions;
handleDelete: (bypassConfirm?: boolean) => void;
onPopoutToggle?: (isOpen: boolean) => void;
readonlyPreview?: boolean;
suppressMessageActions?: boolean;
onHeadingActivate?: () => void;
}