fix: remove copy link, convert mute to PopOut submenu

Copy Link removed — invite link is already in the invite modal.

Flat mute duration items replaced with a single "Mute →" MenuItem
that opens a PopOut submenu (Right/Start) with the 5 durations:
15 minutes / 1 hour / 8 hours / 24 hours / Indefinitely.
Anchor uses RectCords pattern (e.currentTarget.getBoundingClientRect)
matching the existing menu pattern in this file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 17:51:43 -04:00
parent 657ca3a5ca
commit 08e7f33cba
+52 -68
View File
@@ -260,7 +260,7 @@ const RoomNavItemMenu = forwardRef<HTMLDivElement, RoomNavItemMenuProps>(
const space = useSpaceOptionally();
const [invitePrompt, setInvitePrompt] = useState(false);
const [copiedLink, setCopiedLink] = useState(false);
const [muteMenuAnchor, setMuteMenuAnchor] = useState<RectCords>();
const isServerNotice = room.getType() === 'm.server_notice';
const isFavorite = !!room.tags?.['m.favourite'];
@@ -279,14 +279,6 @@ const RoomNavItemMenu = forwardRef<HTMLDivElement, RoomNavItemMenuProps>(
requestClose();
};
const handleCopyRoomLink = () => {
const roomAlias = room.getCanonicalAlias() ?? room.roomId;
const link = `https://matrix.to/#/${encodeURIComponent(roomAlias)}`;
navigator.clipboard.writeText(link).catch(() => {});
setCopiedLink(true);
setTimeout(() => setCopiedLink(false), 1500);
};
const handleMuteFor = useCallback(
async (durationMs: number | null) => {
const { setRoomNotificationPreference } =
@@ -348,16 +340,6 @@ const RoomNavItemMenu = forwardRef<HTMLDivElement, RoomNavItemMenuProps>(
Mark as Read
</Text>
</MenuItem>
<MenuItem
onClick={handleCopyRoomLink}
size="300"
after={<Icon size="100" src={Icons.Link} />}
radii="300"
>
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
{copiedLink ? 'Copied!' : 'Copy Link'}
</Text>
</MenuItem>
<RoomNotificationModeSwitcher roomId={room.roomId} value={notificationMode}>
{(handleOpen, opened, changing) => (
<MenuItem
@@ -384,56 +366,58 @@ const RoomNavItemMenu = forwardRef<HTMLDivElement, RoomNavItemMenuProps>(
<>
<Line variant="Surface" size="300" />
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
<MenuItem
size="300"
after={<Icon size="100" src={Icons.BellMute} />}
radii="300"
onClick={() => handleMuteFor(15 * 60 * 1000)}
<PopOut
anchor={muteMenuAnchor}
position="Right"
align="Start"
offset={4}
content={
<FocusTrap
focusTrapOptions={{
initialFocus: false,
onDeactivate: () => setMuteMenuAnchor(undefined),
clickOutsideDeactivates: true,
escapeDeactivates: stopPropagation,
}}
>
<Menu style={{ maxWidth: toRem(160), width: '100vw' }}>
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
{[
{ label: '15 minutes', ms: 15 * 60 * 1000 },
{ label: '1 hour', ms: 60 * 60 * 1000 },
{ label: '8 hours', ms: 8 * 60 * 60 * 1000 },
{ label: '24 hours', ms: 24 * 60 * 60 * 1000 },
{ label: 'Indefinitely', ms: null },
].map(({ label, ms }) => (
<MenuItem
key={label}
size="300"
radii="300"
onClick={() => handleMuteFor(ms)}
>
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
{label}
</Text>
</MenuItem>
))}
</Box>
</Menu>
</FocusTrap>
}
>
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
Mute for 15m
</Text>
</MenuItem>
<MenuItem
size="300"
after={<Icon size="100" src={Icons.BellMute} />}
radii="300"
onClick={() => handleMuteFor(60 * 60 * 1000)}
>
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
Mute for 1h
</Text>
</MenuItem>
<MenuItem
size="300"
after={<Icon size="100" src={Icons.BellMute} />}
radii="300"
onClick={() => handleMuteFor(8 * 60 * 60 * 1000)}
>
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
Mute for 8h
</Text>
</MenuItem>
<MenuItem
size="300"
after={<Icon size="100" src={Icons.BellMute} />}
radii="300"
onClick={() => handleMuteFor(24 * 60 * 60 * 1000)}
>
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
Mute for 24h
</Text>
</MenuItem>
<MenuItem
size="300"
after={<Icon size="100" src={Icons.BellMute} />}
radii="300"
onClick={() => handleMuteFor(null)}
>
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
Mute indefinitely
</Text>
</MenuItem>
<MenuItem
size="300"
after={<Icon size="100" src={Icons.ChevronRight} />}
radii="300"
aria-pressed={!!muteMenuAnchor}
onClick={(e) => setMuteMenuAnchor(e.currentTarget.getBoundingClientRect())}
>
<Icon size="100" src={Icons.BellMute} />
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
Mute
</Text>
</MenuItem>
</PopOut>
</Box>
</>
)}