diff --git a/src/app/features/room/RoomViewHeader.tsx b/src/app/features/room/RoomViewHeader.tsx index d5c6a5ac5..08f4e95d7 100644 --- a/src/app/features/room/RoomViewHeader.tsx +++ b/src/app/features/room/RoomViewHeader.tsx @@ -107,6 +107,10 @@ const RoomMenu = forwardRef( const [reportRoomOpen, setReportRoomOpen] = useState(false); const [bookmarksOpen, setBookmarksOpen] = useAtom(bookmarksPanelAtom); const [mobileMembers, setMobileMembers] = useAtom(mobileMembersPanelAtom); + // [Gitea #165 / #211] Threads list and Widgets had desktop-only header + // buttons and no mobile entry point at all. + const [threadsList, setThreadsList] = useAtom(threadsListAtom); + const [widgets, setWidgets] = useAtom(widgetsPanelAtom); const handleMarkAsRead = () => { markAsRead(mx, room.roomId, hideActivity); @@ -226,6 +230,38 @@ const RoomMenu = forwardRef( )} + {screenSize === ScreenSize.Mobile && ( + { + setThreadsList(!threadsList); + requestClose(); + }} + size="300" + after={} + radii="300" + aria-pressed={threadsList} + > + + Threads + + + )} + {screenSize === ScreenSize.Mobile && ( + { + setWidgets(!widgets); + requestClose(); + }} + size="300" + after={} + radii="300" + aria-pressed={widgets} + > + + Widgets + + + )} {!isServerNotice && ( 0; - const { replyEventId, threadRootId } = mEvent; + const { replyEventId } = mEvent; const forwardedMeta = getForwardedMeta(mEvent.getContent()); + // Inside the panel every reply carries the spec's *fallback* reply + // relation to the thread root (`is_falling_back: true`) so non-threaded + // clients can render it as a reply. Here the root is already at the top, + // so that quote — and the "Thread" chip — is pure noise on every row + // (Gitea #165). Only a genuine reply-to-a-reply keeps its quote. + const relation = mEvent.getWireContent()?.['m.relates_to'] as + | { is_falling_back?: boolean } + | undefined; + const genuineReplyId = + replyEventId && !(relation?.is_falling_back && replyEventId === thread.id) + ? replyEventId + : undefined; return ( navigateRoom(forwardedMeta.room_id, forwardedMeta.event_id)} /> )} - {replyEventId && ( + {genuineReplyId && (