diff --git a/res/img/element-icons/message/view-in-timeline.svg b/res/img/element-icons/message/view-in-timeline.svg new file mode 100644 index 0000000000..9f05950ce0 --- /dev/null +++ b/res/img/element-icons/message/view-in-timeline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index bb31c32877..180a870cd5 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -139,7 +139,7 @@ export default class ThreadView extends React.Component { sendReadReceiptOnLoad={false} // No RR support in thread's MVP timelineSet={this.state?.thread?.timelineSet} showUrlPreview={true} - tileShape={TileShape.Notif} + tileShape={TileShape.Thread} empty={
empty
} alwaysShowTimestamps={true} layout={Layout.Group} diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index e835584387..06817b910a 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -128,6 +128,11 @@ const ReactButton: React.FC = ({ mxEvent, reactions, onFocusC ; }; +export enum ActionBarRenderingContext { + Room, + Thread +} + interface IMessageActionBarProps { mxEvent: MatrixEvent; reactions?: Relations; @@ -135,15 +140,20 @@ interface IMessageActionBarProps { getTile: () => any | null; getReplyThread: () => ReplyThread | undefined; permalinkCreator?: RoomPermalinkCreator; - onFocusChange: (menuDisplayed: boolean) => void; - isQuoteExpanded?: boolean; + onFocusChange?: (menuDisplayed: boolean) => void; toggleThreadExpanded: () => void; + renderingContext?: ActionBarRenderingContext; + isQuoteExpanded?: boolean; } @replaceableComponent("views.messages.MessageActionBar") export default class MessageActionBar extends React.PureComponent { public static contextType = RoomContext; + public static defaultProps = { + renderingContext: ActionBarRenderingContext.Room, + }; + public componentDidMount(): void { if (this.props.mxEvent.status && this.props.mxEvent.status !== EventStatus.SENT) { this.props.mxEvent.on("Event.status", this.onSent); @@ -288,7 +298,7 @@ export default class MessageActionBar extends React.PureComponent { } } + const renderingContext = this.props.tileShape === TileShape.Thread + ? ActionBarRenderingContext.Thread + : ActionBarRenderingContext.Room; const actionBar = !isEditing ? { getTile={this.getTile} getReplyThread={this.getReplyThread} onFocusChange={this.onActionBarFocusChange} + renderingContext={renderingContext} isQuoteExpanded={isQuoteExpanded} toggleThreadExpanded={() => this.setQuoteExpanded(!isQuoteExpanded)} /> : undefined; @@ -1170,6 +1175,40 @@ export default class EventTile extends React.Component { , ]); } + case TileShape.Thread: { + const room = this.context.getRoom(this.props.mxEvent.getRoomId()); + return React.createElement(this.props.as || "li", { + "className": classes, + "aria-live": ariaLive, + "aria-atomic": true, + "data-scroll-tokens": scrollToken, + }, [ + , + , +
+ + { actionBar } +
, + ]); + } case TileShape.FileGrid: { return React.createElement(this.props.as || "li", { "className": classes,