From d3dd37dc3bf1f7fa4994510fe378703be6122b9a Mon Sep 17 00:00:00 2001 From: Ajay Bura <32841439+ajbura@users.noreply.github.com> Date: Sun, 14 Apr 2024 17:27:19 +0530 Subject: [PATCH] add room header menu --- src/app/features/room/RoomViewHeader.tsx | 341 +++++++++++++++++------ 1 file changed, 251 insertions(+), 90 deletions(-) diff --git a/src/app/features/room/RoomViewHeader.tsx b/src/app/features/room/RoomViewHeader.tsx index a4a23866..05632e86 100644 --- a/src/app/features/room/RoomViewHeader.tsx +++ b/src/app/features/room/RoomViewHeader.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { MouseEventHandler, forwardRef, useState } from 'react'; import FocusTrap from 'focus-trap-react'; import { Box, @@ -12,8 +12,16 @@ import { Icons, Tooltip, TooltipProvider, + Menu, + MenuItem, + toRem, + config, + Line, + PopOut, + RectCords, } from 'folds'; -import { useNavigate } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { Room } from 'matrix-js-sdk'; import { useStateEvent } from '../../hooks/useStateEvent'; import { PageHeader } from '../../components/page'; @@ -28,16 +36,138 @@ import { useRoom } from '../../hooks/useRoom'; import { useSetSetting } from '../../state/hooks/settings'; import { settingsAtom } from '../../state/settings'; import { useSpaceOptionally } from '../../hooks/useSpace'; -import { getHomeSearchPath, getSpaceSearchPath, withSearchParam } from '../../pages/pathUtils'; +import { + getHomeSearchPath, + getOriginBaseUrl, + getSpaceSearchPath, + joinPathComponent, + withOriginBaseUrl, + withSearchParam, +} from '../../pages/pathUtils'; import { getCanonicalAliasOrRoomId } from '../../utils/matrix'; import { _SearchPathSearchParams } from '../../pages/paths'; import * as css from './RoomViewHeader.css'; +import { useRoomUnread } from '../../state/hooks/unread'; +import { usePowerLevelsAPI } from '../../hooks/usePowerLevels'; +import { markAsRead } from '../../../client/action/notifications'; +import { roomToUnreadAtom } from '../../state/room/roomToUnread'; +import { openInviteUser } from '../../../client/action/navigation'; +import { copyToClipboard } from '../../utils/dom'; + +type RoomMenuProps = { + room: Room; + linkPath: string; + requestClose: () => void; +}; +const RoomMenu = forwardRef( + ({ room, linkPath, requestClose }, ref) => { + const mx = useMatrixClient(); + const unread = useRoomUnread(room.roomId, roomToUnreadAtom); + const { getPowerLevel, canDoAction } = usePowerLevelsAPI(); + const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? '')); + + const handleMarkAsRead = () => { + markAsRead(room.roomId); + requestClose(); + }; + + const handleInvite = () => { + openInviteUser(room.roomId); + requestClose(); + }; + + const handleCopyLink = () => { + copyToClipboard(withOriginBaseUrl(getOriginBaseUrl(), linkPath)); + requestClose(); + }; + + const handleRoomSettings = () => { + alert('Work In Progress...'); + requestClose(); + }; + + const handleLeaveRoom = () => { + mx.leave(room.roomId); + requestClose(); + }; + + return ( + + + } + radii="300" + disabled={!unread} + > + + Mark as Read + + + + + + } + radii="300" + disabled={!canInvite} + > + + Invite + + + } + radii="300" + > + + Copy Link + + + } + radii="300" + > + + Room Settings + + + + + + } + radii="300" + > + + Leave Room + + + + + ); + } +); export function RoomViewHeader() { const navigate = useNavigate(); const mx = useMatrixClient(); const room = useRoom(); const space = useSpaceOptionally(); + const [menuAnchor, setMenuAnchor] = useState(); const encryptionEvent = useStateEvent(room, StateEvent.RoomEncryption); const ecryptedRoom = !!encryptionEvent; @@ -45,6 +175,8 @@ export function RoomViewHeader() { const topic = topicEvent?.getContent().topic as string | undefined | null; const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer'); + const location = useLocation(); + const currentPath = joinPathComponent(location); const handleSearchClick = () => { const searchParams: _SearchPathSearchParams = { @@ -56,108 +188,137 @@ export function RoomViewHeader() { navigate(withSearchParam(path, searchParams)); }; + const handleOpenMenu: MouseEventHandler = (evt) => { + setMenuAnchor(evt.currentTarget.getBoundingClientRect()); + }; + return ( - - - {nameInitials(room.name)}} - /> - - - - {room.name} - - {topic && ( - - {(viewTopic, setViewTopic) => ( - <> - }> - - setViewTopic(false), - }} - > - setViewTopic(false)} - /> - - - - setViewTopic(true)} - className={css.HeaderTopic} - size="T200" - priority="300" - truncate - > - {topic} - - - )} - - )} + + + + {nameInitials(room.name)}} + /> + + + + {room.name} + + {topic && ( + + {(viewTopic, setViewTopic) => ( + <> + }> + + setViewTopic(false), + }} + > + setViewTopic(false)} + /> + + + + setViewTopic(true)} + className={css.HeaderTopic} + size="T200" + priority="300" + truncate + > + {topic} + + + )} + + )} + - - - {!ecryptedRoom && ( + + {!ecryptedRoom && ( + + Search + + } + > + {(triggerRef) => ( + + + + )} + + )} - Search + Members } > {(triggerRef) => ( - - + setPeopleDrawer((drawer) => !drawer)}> + )} - )} - - Members - - } - > - {(triggerRef) => ( - setPeopleDrawer((drawer) => !drawer)}> - - - )} - - - More Options - - } - > - {(triggerRef) => ( - - - - )} - + + More Options + + } + > + {(triggerRef) => ( + + + + )} + + setMenuAnchor(undefined), + clickOutsideDeactivates: true, + isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown', + isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', + }} + > + setMenuAnchor(undefined)} + /> + + } + /> + );