Add room notifications context menu and non-default indicator to RoomTile2
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
adf186f568
commit
54419878fa
3 changed files with 111 additions and 17 deletions
|
@ -92,20 +92,17 @@ limitations under the License.
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The menu button is hidden by default
|
|
||||||
// TODO: [Notifications] Use mx_RoomTile2_notificationsButton, similar to the following approach:
|
|
||||||
// https://github.com/matrix-org/matrix-react-sdk/blob/2180a56074f3698fc0241c309a72ba6cad802d1c/res/css/views/rooms/_RoomSublist2.scss#L48-L76
|
|
||||||
// You'll need to do the same down below on the &:hover selector for the tile.
|
|
||||||
// See https://github.com/vector-im/riot-web/issues/13961.
|
|
||||||
// ... also remove this 5 line TODO comment.
|
|
||||||
.mx_RoomTile2_menuButton,
|
.mx_RoomTile2_menuButton,
|
||||||
.mx_RoomTile2_notificationsButton {
|
.mx_RoomTile2_notificationsButton {
|
||||||
width: 0;
|
width: 20px;
|
||||||
height: 0;
|
height: 20px;
|
||||||
visibility: hidden;
|
margin: auto 0 auto 8px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: none;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
content: '';
|
content: '';
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
|
@ -117,8 +114,11 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_RoomTile2_notificationsButton.mx_RoomTile2_notificationsButton_show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_RoomTile2_menuButton::before {
|
.mx_RoomTile2_menuButton::before {
|
||||||
left: 1px; // this is off-center to align it with the badges
|
|
||||||
mask-image: url('$(res)/img/feather-customised/more-horizontal.svg');
|
mask-image: url('$(res)/img/feather-customised/more-horizontal.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,11 +131,9 @@ limitations under the License.
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_RoomTile2_notificationsButton,
|
||||||
.mx_RoomTile2_menuButton {
|
.mx_RoomTile2_menuButton {
|
||||||
width: 16px;
|
display: block;
|
||||||
height: 16px;
|
|
||||||
visibility: visible;
|
|
||||||
margin: auto 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,6 +156,17 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We use these both in context menus and the room tiles
|
||||||
|
.mx_RoomTile2_iconBell::before {
|
||||||
|
mask-image: url('$(res)/img/feather-customised/bell.svg');
|
||||||
|
}
|
||||||
|
.mx_RoomTile2_iconBellDot::before {
|
||||||
|
mask-image: url('$(res)/img/feather-customised/bell-notification.custom.svg');
|
||||||
|
}
|
||||||
|
.mx_RoomTile2_iconBellCrossed::before {
|
||||||
|
mask-image: url('$(res)/img/feather-customised/bell-crossed.svg');
|
||||||
|
}
|
||||||
|
|
||||||
.mx_RoomTile2_contextMenu {
|
.mx_RoomTile2_contextMenu {
|
||||||
.mx_RoomTile2_contextMenu_redRow {
|
.mx_RoomTile2_contextMenu_redRow {
|
||||||
.mx_AccessibleButton {
|
.mx_AccessibleButton {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { ContextMenu, ContextMenuButton } from "../../structures/ContextMenu";
|
||||||
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
|
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
|
||||||
import { MessagePreviewStore } from "../../../stores/room-list/MessagePreviewStore";
|
import { MessagePreviewStore } from "../../../stores/room-list/MessagePreviewStore";
|
||||||
import RoomTileIcon from "./RoomTileIcon";
|
import RoomTileIcon from "./RoomTileIcon";
|
||||||
|
import { getRoomNotifsState, ALL_MESSAGES, ALL_MESSAGES_LOUD, MENTIONS_ONLY, MUTE } from "../../../RoomNotifs";
|
||||||
|
|
||||||
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
|
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
|
||||||
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
|
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
|
||||||
|
@ -61,6 +62,7 @@ interface IState {
|
||||||
hover: boolean;
|
hover: boolean;
|
||||||
notificationState: INotificationState;
|
notificationState: INotificationState;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
|
notificationsMenuDisplayed: boolean;
|
||||||
generalMenuDisplayed: boolean;
|
generalMenuDisplayed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +74,7 @@ export const contextMenuBelow = (elementRect) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class RoomTile2 extends React.Component<IProps, IState> {
|
export default class RoomTile2 extends React.Component<IProps, IState> {
|
||||||
|
private notificationsMenuButtonRef: React.RefObject<HTMLButtonElement> = createRef();
|
||||||
private generalMenuButtonRef: React.RefObject<HTMLButtonElement> = createRef();
|
private generalMenuButtonRef: React.RefObject<HTMLButtonElement> = createRef();
|
||||||
|
|
||||||
// TODO: a11y: https://github.com/vector-im/riot-web/issues/14180
|
// TODO: a11y: https://github.com/vector-im/riot-web/issues/14180
|
||||||
|
@ -83,6 +86,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
||||||
hover: false,
|
hover: false,
|
||||||
notificationState: new TagSpecificNotificationState(this.props.room, this.props.tag),
|
notificationState: new TagSpecificNotificationState(this.props.room, this.props.tag),
|
||||||
selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId,
|
selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId,
|
||||||
|
notificationsMenuDisplayed: false,
|
||||||
generalMenuDisplayed: false,
|
generalMenuDisplayed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,6 +121,18 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
||||||
this.setState({selected: isActive});
|
this.setState({selected: isActive});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onNotificationsMenuOpenClick = (ev: InputEvent) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.setState({notificationsMenuDisplayed: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
private onCloseNotificationsMenu = (ev: InputEvent) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.setState({notificationsMenuDisplayed: false});
|
||||||
|
};
|
||||||
|
|
||||||
private onGeneralMenuOpenClick = (ev: InputEvent) => {
|
private onGeneralMenuOpenClick = (ev: InputEvent) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
@ -159,12 +175,78 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
||||||
this.setState({generalMenuDisplayed: false}); // hide the menu
|
this.setState({generalMenuDisplayed: false}); // hide the menu
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private renderNotificationsMenu(): React.ReactElement {
|
||||||
|
if (this.props.isMinimized) return null; // no menu when minimized
|
||||||
|
|
||||||
|
let contextMenu = null;
|
||||||
|
if (this.state.notificationsMenuDisplayed) {
|
||||||
|
const elementRect = this.notificationsMenuButtonRef.current.getBoundingClientRect();
|
||||||
|
contextMenu = (
|
||||||
|
<ContextMenu {...contextMenuBelow(elementRect)} onFinished={this.onCloseNotificationsMenu}>
|
||||||
|
<div className="mx_IconizedContextMenu mx_IconizedContextMenu_compact mx_RoomTile2_contextMenu">
|
||||||
|
<div className="mx_IconizedContextMenu_optionList">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<AccessibleButton onClick={console.log}>
|
||||||
|
<span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconBell" />
|
||||||
|
<span>{_t("All messages")}</span>
|
||||||
|
</AccessibleButton>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<AccessibleButton onClick={console.log}>
|
||||||
|
<span className="mx_IconizedContextMenu_icon" />
|
||||||
|
<span>{_t("Default")}</span>
|
||||||
|
</AccessibleButton>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<AccessibleButton onClick={console.log}>
|
||||||
|
<span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconBellDot" />
|
||||||
|
<span>{_t("Mentions & Keywords")}</span>
|
||||||
|
</AccessibleButton>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<AccessibleButton onClick={console.log}>
|
||||||
|
<span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconBellCrossed" />
|
||||||
|
<span>{_t("None")}</span>
|
||||||
|
</AccessibleButton>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ContextMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = getRoomNotifsState(this.props.room.roomId);
|
||||||
|
const classes = classNames("mx_RoomTile2_notificationsButton", {
|
||||||
|
// Show bell icon for the default case too.
|
||||||
|
mx_RoomTile2_iconBell: state === ALL_MESSAGES_LOUD || state === ALL_MESSAGES,
|
||||||
|
mx_RoomTile2_iconBellDot: state === MENTIONS_ONLY,
|
||||||
|
mx_RoomTile2_iconBellCrossed: state === MUTE,
|
||||||
|
// XXX: RoomNotifs assumes ALL_MESSAGES is default, this is wrong,
|
||||||
|
// but cannot be fixed until FTUE Notifications lands.
|
||||||
|
mx_RoomTile2_notificationsButton_show: state !== ALL_MESSAGES,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<ContextMenuButton
|
||||||
|
className={classes}
|
||||||
|
onClick={this.onNotificationsMenuOpenClick}
|
||||||
|
inputRef={this.notificationsMenuButtonRef}
|
||||||
|
label={_t("Notification options")}
|
||||||
|
isExpanded={this.state.notificationsMenuDisplayed}
|
||||||
|
/>
|
||||||
|
{contextMenu}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private renderGeneralMenu(): React.ReactElement {
|
private renderGeneralMenu(): React.ReactElement {
|
||||||
if (this.props.isMinimized) return null; // no menu when minimized
|
if (this.props.isMinimized) return null; // no menu when minimized
|
||||||
|
|
||||||
let contextMenu = null;
|
let contextMenu = null;
|
||||||
if (this.state.generalMenuDisplayed) {
|
if (this.state.generalMenuDisplayed) {
|
||||||
// The context menu appears within the list, so use the room tile as a reference point
|
|
||||||
const elementRect = this.generalMenuButtonRef.current.getBoundingClientRect();
|
const elementRect = this.generalMenuButtonRef.current.getBoundingClientRect();
|
||||||
contextMenu = (
|
contextMenu = (
|
||||||
<ContextMenu {...contextMenuBelow(elementRect)} onFinished={this.onCloseGeneralMenu}>
|
<ContextMenu {...contextMenuBelow(elementRect)} onFinished={this.onCloseGeneralMenu}>
|
||||||
|
@ -227,7 +309,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
'mx_RoomTile2': true,
|
'mx_RoomTile2': true,
|
||||||
'mx_RoomTile2_selected': this.state.selected,
|
'mx_RoomTile2_selected': this.state.selected,
|
||||||
'mx_RoomTile2_hasMenuOpen': this.state.generalMenuDisplayed,
|
'mx_RoomTile2_hasMenuOpen': this.state.generalMenuDisplayed || this.state.notificationsMenuDisplayed,
|
||||||
'mx_RoomTile2_minimized': this.props.isMinimized,
|
'mx_RoomTile2_minimized': this.props.isMinimized,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -298,6 +380,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
||||||
<div className="mx_RoomTile2_badgeContainer">
|
<div className="mx_RoomTile2_badgeContainer">
|
||||||
{badge}
|
{badge}
|
||||||
</div>
|
</div>
|
||||||
|
{this.renderNotificationsMenu()}
|
||||||
{this.renderGeneralMenu()}
|
{this.renderGeneralMenu()}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1218,6 +1218,9 @@
|
||||||
"%(count)s unread messages.|one": "1 unread message.",
|
"%(count)s unread messages.|one": "1 unread message.",
|
||||||
"Unread mentions.": "Unread mentions.",
|
"Unread mentions.": "Unread mentions.",
|
||||||
"Unread messages.": "Unread messages.",
|
"Unread messages.": "Unread messages.",
|
||||||
|
"All messages": "All messages",
|
||||||
|
"Mentions & Keywords": "Mentions & Keywords",
|
||||||
|
"Notification options": "Notification options",
|
||||||
"Favourite": "Favourite",
|
"Favourite": "Favourite",
|
||||||
"Low Priority": "Low Priority",
|
"Low Priority": "Low Priority",
|
||||||
"Leave Room": "Leave Room",
|
"Leave Room": "Leave Room",
|
||||||
|
@ -1894,7 +1897,6 @@
|
||||||
"Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
|
"Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
|
||||||
"Notification settings": "Notification settings",
|
"Notification settings": "Notification settings",
|
||||||
"All messages (noisy)": "All messages (noisy)",
|
"All messages (noisy)": "All messages (noisy)",
|
||||||
"All messages": "All messages",
|
|
||||||
"Mentions only": "Mentions only",
|
"Mentions only": "Mentions only",
|
||||||
"Leave": "Leave",
|
"Leave": "Leave",
|
||||||
"Forget": "Forget",
|
"Forget": "Forget",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue