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,