diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss index 89ab85e146..d210e118a2 100644 --- a/res/css/views/rooms/_RoomList.scss +++ b/res/css/views/rooms/_RoomList.scss @@ -17,3 +17,10 @@ limitations under the License. .mx_RoomList { padding-right: 7px; // width of the scrollbar, to line things up } + +.mx_RoomList_iconPlus::before { + mask-image: url('$(res)/img/element-icons/roomlist/plus.svg'); +} +.mx_RoomList_iconExplore::before { + mask-image: url('$(res)/img/element-icons/roomlist/explore.svg'); +} diff --git a/res/css/views/rooms/_RoomSublist.scss b/res/css/views/rooms/_RoomSublist.scss index fe80dfca22..543940fb78 100644 --- a/res/css/views/rooms/_RoomSublist.scss +++ b/res/css/views/rooms/_RoomSublist.scss @@ -120,7 +120,7 @@ limitations under the License. } .mx_RoomSublist_auxButton::before { - mask-image: url('$(res)/img/feather-customised/plus.svg'); + mask-image: url('$(res)/img/element-icons/roomlist/plus.svg'); } .mx_RoomSublist_menuButton::before { diff --git a/res/img/element-icons/roomlist/explore.svg b/res/img/element-icons/roomlist/explore.svg new file mode 100644 index 0000000000..3786ce1153 --- /dev/null +++ b/res/img/element-icons/roomlist/explore.svg @@ -0,0 +1,4 @@ + + + + diff --git a/res/img/element-icons/roomlist/plus.svg b/res/img/element-icons/roomlist/plus.svg new file mode 100644 index 0000000000..f6d80ac7ef --- /dev/null +++ b/res/img/element-icons/roomlist/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index 0d90c04e13..0d3bbb7f8b 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -43,6 +43,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import CustomRoomTagStore from "../../../stores/CustomRoomTagStore"; import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays"; import { objectShallowClone, objectWithOnly } from "../../../utils/objects"; +import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../context_menus/IconizedContextMenu"; interface IProps { onKeyDown: (ev: React.KeyboardEvent) => void; @@ -81,6 +82,7 @@ interface ITagAesthetics { sectionLabelRaw?: string; addRoomLabel?: string; onAddRoom?: (dispatcher?: Dispatcher) => void; + addRoomContextMenu?: (onFinished: () => void) => React.ReactNode; isInvite: boolean; defaultHidden: boolean; } @@ -112,9 +114,30 @@ const TAG_AESTHETICS: { sectionLabel: _td("Rooms"), isInvite: false, defaultHidden: false, - addRoomLabel: _td("Create room"), - onAddRoom: (dispatcher?: Dispatcher) => { - (dispatcher || defaultDispatcher).dispatch({action: 'view_create_room'}) + addRoomLabel: _td("Add room"), + addRoomContextMenu: (onFinished: () => void) => { + return + { + e.preventDefault(); + e.stopPropagation(); + onFinished(); + defaultDispatcher.dispatch({action: "view_create_room"}); + }} + /> + { + e.preventDefault(); + e.stopPropagation(); + onFinished(); + defaultDispatcher.fire(Action.ViewRoomDirectory); + }} + /> + ; }, }, [DefaultTagID.LowPriority]: { @@ -324,6 +347,7 @@ export default class RoomList extends React.PureComponent { label={aesthetics.sectionLabelRaw ? aesthetics.sectionLabelRaw : _t(aesthetics.sectionLabel)} onAddRoom={aesthetics.onAddRoom} addRoomLabel={aesthetics.addRoomLabel ? _t(aesthetics.addRoomLabel) : aesthetics.addRoomLabel} + addRoomContextMenu={aesthetics.addRoomContextMenu} isMinimized={this.props.isMinimized} onResize={this.props.onResize} extraBadTilesThatShouldntExist={extraTiles} diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index b2337c8c22..1e7ba3f77a 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -50,6 +50,7 @@ import { arrayFastClone, arrayHasOrderChange } from "../../../utils/arrays"; import { objectExcluding, objectHasDiff } from "../../../utils/objects"; import TemporaryTile from "./TemporaryTile"; import { ListNotificationState } from "../../../stores/notifications/ListNotificationState"; +import IconizedContextMenu from "../context_menus/IconizedContextMenu"; const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS @@ -65,6 +66,7 @@ interface IProps { startAsHidden: boolean; label: string; onAddRoom?: () => void; + addRoomContextMenu?: (onFinished: () => void) => React.ReactNode; addRoomLabel: string; isMinimized: boolean; tagId: TagID; @@ -87,6 +89,7 @@ type PartialDOMRect = Pick; interface IState { contextMenuPosition: PartialDOMRect; + addRoomContextMenuPosition: PartialDOMRect; isResizing: boolean; isExpanded: boolean; // used for the for expand of the sublist when the room list is being filtered height: number; @@ -112,6 +115,7 @@ export default class RoomSublist extends React.Component { this.notificationState = RoomNotificationStateStore.instance.getListState(this.props.tagId); this.state = { contextMenuPosition: null, + addRoomContextMenuPosition: null, isResizing: false, isExpanded: this.isBeingFiltered ? this.isBeingFiltered : !this.layout.isCollapsed, height: 0, // to be fixed in a moment, we need `rooms` to calculate this. @@ -376,10 +380,21 @@ export default class RoomSublist extends React.Component { }); }; + private onAddRoomContextMenu = (ev: React.MouseEvent) => { + ev.preventDefault(); + ev.stopPropagation(); + const target = ev.target as HTMLButtonElement; + this.setState({addRoomContextMenuPosition: target.getBoundingClientRect()}); + }; + private onCloseMenu = () => { this.setState({contextMenuPosition: null}); }; + private onCloseAddRoomMenu = () => { + this.setState({addRoomContextMenuPosition: null}); + }; + private onUnreadFirstChanged = async () => { const isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance; const newAlgorithm = isUnreadFirst ? ListAlgorithm.Natural : ListAlgorithm.Importance; @@ -594,6 +609,18 @@ export default class RoomSublist extends React.Component { ); + } else if (this.state.addRoomContextMenuPosition) { + contextMenu = ( + + {this.props.addRoomContextMenu(this.onCloseAddRoomMenu)} + + ); } return ( @@ -637,9 +664,21 @@ export default class RoomSublist extends React.Component { tabIndex={tabIndex} onClick={this.onAddRoom} className="mx_RoomSublist_auxButton" + tooltipClassName="mx_RoomSublist_addRoomTooltip" aria-label={this.props.addRoomLabel || _t("Add room")} title={this.props.addRoomLabel} - tooltipClassName={"mx_RoomSublist_addRoomTooltip"} + /> + ); + } else if (this.props.addRoomContextMenu) { + addRoomButton = ( + ); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b636b5470e..b311a0cd5b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1111,7 +1111,9 @@ "People": "People", "Start chat": "Start chat", "Rooms": "Rooms", - "Create room": "Create room", + "Add room": "Add room", + "Create new room": "Create new room", + "Explore public rooms": "Explore public rooms", "Low priority": "Low priority", "System Alerts": "System Alerts", "Historical": "Historical", @@ -1168,7 +1170,6 @@ "List options": "List options", "Jump to first unread room.": "Jump to first unread room.", "Jump to first invite.": "Jump to first invite.", - "Add room": "Add room", "Show %(count)s more|other": "Show %(count)s more", "Show %(count)s more|one": "Show %(count)s more", "Use default": "Use default",