diff --git a/res/css/views/right_panel/_RoomSummaryCard.scss b/res/css/views/right_panel/_RoomSummaryCard.scss
index 59b3588283..14e5dc654f 100644
--- a/res/css/views/right_panel/_RoomSummaryCard.scss
+++ b/res/css/views/right_panel/_RoomSummaryCard.scss
@@ -251,6 +251,10 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/room/files.svg');
}
+.mx_RoomSummaryCard_icon_pins::before {
+ mask-image: url('$(res)/img/element-icons/room/pin-upright.svg');
+}
+
.mx_RoomSummaryCard_icon_threads::before {
mask-image: url('$(res)/img/element-icons/message/thread.svg');
}
diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss
index e11bde1f52..9253a25e32 100644
--- a/res/css/views/rooms/_RoomTile.scss
+++ b/res/css/views/rooms/_RoomTile.scss
@@ -213,6 +213,10 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/room/files.svg');
}
+ .mx_RoomTile_iconPins::before {
+ mask-image: url('$(res)/img/element-icons/room/pin-upright.svg');
+ }
+
.mx_RoomTile_iconWidgets::before {
mask-image: url('$(res)/img/element-icons/room/apps.svg');
}
diff --git a/src/components/views/context_menus/RoomContextMenu.tsx b/src/components/views/context_menus/RoomContextMenu.tsx
index 290b53c1d8..cc7a567f59 100644
--- a/src/components/views/context_menus/RoomContextMenu.tsx
+++ b/src/components/views/context_menus/RoomContextMenu.tsx
@@ -36,6 +36,8 @@ import { EchoChamber } from "../../../stores/local-echo/EchoChamber";
import { RoomNotifState } from "../../../RoomNotifs";
import Modal from "../../../Modal";
import ExportDialog from "../dialogs/ExportDialog";
+import { useSettingValue } from "../../../hooks/useSettings";
+import { usePinnedEvents } from "../right_panel/PinnedMessagesCard";
import RoomViewStore from "../../../stores/RoomViewStore";
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog";
@@ -228,6 +230,29 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
/>;
}
+ const pinningEnabled = useSettingValue("feature_pinning");
+ const pinCount = usePinnedEvents(pinningEnabled && room)?.length;
+
+ let pinsOption: JSX.Element;
+ if (pinningEnabled) {
+ pinsOption = {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ ensureViewingRoom(ev);
+ RightPanelStore.instance.pushCard({ phase: RightPanelPhases.PinnedMessages }, false);
+ onFinished();
+ }}
+ label={_t("Pinned")}
+ iconClassName="mx_RoomTile_iconPins"
+ >
+ { pinCount > 0 &&
+ { pinCount }
+ }
+ ;
+ }
+
const onTagRoom = (ev: ButtonEvent, tagId: TagID) => {
ev.preventDefault();
ev.stopPropagation();
@@ -278,6 +303,8 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
iconClassName="mx_RoomTile_iconFiles"
/>
+ { pinsOption }
+
{
ev.preventDefault();
diff --git a/src/components/views/right_panel/RoomHeaderButtons.tsx b/src/components/views/right_panel/RoomHeaderButtons.tsx
index acca6f935c..aa2a8ffd63 100644
--- a/src/components/views/right_panel/RoomHeaderButtons.tsx
+++ b/src/components/views/right_panel/RoomHeaderButtons.tsx
@@ -82,7 +82,7 @@ const PinnedMessagesHeaderButton = ({ room, isHighlighted, onClick }: IHeaderBut
const pinningEnabled = useSettingValue("feature_pinning");
const pinnedEvents = usePinnedEvents(pinningEnabled && room);
const readPinnedEvents = useReadPinnedEvents(pinningEnabled && room);
- if (!pinningEnabled) return null;
+ if (!pinnedEvents?.length) return null;
let unreadIndicator;
if (pinnedEvents.some(id => !readPinnedEvents.has(id))) {
diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx
index e3a4f3740f..5942d73bd6 100644
--- a/src/components/views/right_panel/RoomSummaryCard.tsx
+++ b/src/components/views/right_panel/RoomSummaryCard.tsx
@@ -42,6 +42,8 @@ import { UIFeature } from "../../../settings/UIFeature";
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
import WidgetContextMenu from "../context_menus/WidgetContextMenu";
import { useRoomMemberCount } from "../../../hooks/useRoomMembers";
+import { useSettingValue } from "../../../hooks/useSettings";
+import { usePinnedEvents } from "./PinnedMessagesCard";
import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
import RoomName from "../elements/RoomName";
import UIStore from "../../../stores/UIStore";
@@ -239,6 +241,10 @@ const onRoomFilesClick = () => {
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, true);
};
+const onRoomPinsClick = () => {
+ RightPanelStore.instance.pushCard({ phase: RightPanelPhases.PinnedMessages }, true);
+};
+
const onRoomSettingsClick = (ev: ButtonEvent) => {
defaultDispatcher.dispatch({ action: "open_room_settings" });
PosthogTrackers.trackInteraction("WebRightPanelRoomInfoSettingsButton", ev);
@@ -290,6 +296,8 @@ const RoomSummaryCard: React.FC = ({ room, onClose }) => {
;
const memberCount = useRoomMemberCount(room);
+ const pinningEnabled = useSettingValue("feature_pinning");
+ const pinCount = usePinnedEvents(pinningEnabled && room)?.length;
return
@@ -302,6 +310,12 @@ const RoomSummaryCard: React.FC = ({ room, onClose }) => {
+ { pinningEnabled && }
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index e70c96d984..7b8dfad5a7 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1961,6 +1961,7 @@
"Not encrypted": "Not encrypted",
"About": "About",
"Files": "Files",
+ "Pinned": "Pinned",
"Export chat": "Export chat",
"Share room": "Share room",
"Room settings": "Room settings",