diff --git a/res/css/views/context_menus/_MessageContextMenu.scss b/res/css/views/context_menus/_MessageContextMenu.scss index 2ecb93e734..338841cce4 100644 --- a/res/css/views/context_menus/_MessageContextMenu.scss +++ b/res/css/views/context_menus/_MessageContextMenu.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2021 Michael Weimann Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,16 +16,69 @@ limitations under the License. */ .mx_MessageContextMenu { - padding: 6px; -} -.mx_MessageContextMenu_field { - display: block; - padding: 3px 6px 3px 6px; - cursor: pointer; - white-space: nowrap; -} + .mx_IconizedContextMenu_icon { + width: 16px; + height: 16px; + display: block; -.mx_MessageContextMenu_field.mx_MessageContextMenu_fieldSet { - font-weight: bold; + &::before { + content: ''; + width: 16px; + height: 16px; + display: block; + mask-position: center; + mask-size: contain; + mask-repeat: no-repeat; + background: $primary-fg-color; + } + } + + .mx_MessageContextMenu_iconCollapse::before { + mask-image: url('$(res)/img/element-icons/message/chevron-up.svg'); + } + + .mx_MessageContextMenu_iconReport::before { + mask-image: url('$(res)/img/element-icons/warning-badge.svg'); + } + + .mx_MessageContextMenu_iconLink::before { + mask-image: url('$(res)/img/element-icons/link.svg'); + } + + .mx_MessageContextMenu_iconPermalink::before { + mask-image: url('$(res)/img/element-icons/room/share.svg'); + } + + .mx_MessageContextMenu_iconUnhidePreview::before { + mask-image: url('$(res)/img/element-icons/settings/appearance.svg'); + } + + .mx_MessageContextMenu_iconForward::before { + mask-image: url('$(res)/img/element-icons/message/fwd.svg'); + } + + .mx_MessageContextMenu_iconRedact::before { + mask-image: url('$(res)/img/element-icons/trashcan.svg'); + } + + .mx_MessageContextMenu_iconResend::before { + mask-image: url('$(res)/img/element-icons/retry.svg'); + } + + .mx_MessageContextMenu_iconSource::before { + mask-image: url('$(res)/img/element-icons/room/format-bar/code.svg'); + } + + .mx_MessageContextMenu_iconQuote::before { + mask-image: url('$(res)/img/element-icons/room/format-bar/quote.svg'); + } + + .mx_MessageContextMenu_iconPin::before { + mask-image: url('$(res)/img/element-icons/room/pin-upright.svg'); + } + + .mx_MessageContextMenu_iconUnpin::before { + mask-image: url('$(res)/img/element-icons/room/pin.svg'); + } } diff --git a/res/img/element-icons/message/chevron-up.svg b/res/img/element-icons/message/chevron-up.svg new file mode 100644 index 0000000000..4eb5ecc33e --- /dev/null +++ b/res/img/element-icons/message/chevron-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/message/corner-up-right.svg b/res/img/element-icons/message/corner-up-right.svg new file mode 100644 index 0000000000..0b8f961b7b --- /dev/null +++ b/res/img/element-icons/message/corner-up-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/message/fwd.svg b/res/img/element-icons/message/fwd.svg new file mode 100644 index 0000000000..8bcc70d092 --- /dev/null +++ b/res/img/element-icons/message/fwd.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/element-icons/message/link.svg b/res/img/element-icons/message/link.svg new file mode 100644 index 0000000000..c89dd41c23 --- /dev/null +++ b/res/img/element-icons/message/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/message/repeat.svg b/res/img/element-icons/message/repeat.svg new file mode 100644 index 0000000000..c7657b08ed --- /dev/null +++ b/res/img/element-icons/message/repeat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/message/share.svg b/res/img/element-icons/message/share.svg new file mode 100644 index 0000000000..df38c14d63 --- /dev/null +++ b/res/img/element-icons/message/share.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/warning-badge.svg b/res/img/element-icons/warning-badge.svg index 1ae4e40ffe..1c8da9aa8e 100644 --- a/res/img/element-icons/warning-badge.svg +++ b/res/img/element-icons/warning-badge.svg @@ -1,5 +1,32 @@ - - - - + + + + + + image/svg+xml + + + + + + + diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index eef10c995a..5d1aad0600 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -28,7 +28,7 @@ import Resend from '../../../Resend'; import SettingsStore from '../../../settings/SettingsStore'; import { isUrlPermitted } from '../../../HtmlUtils'; import { isContentActionable } from '../../../utils/EventUtils'; -import { MenuItem } from "../../structures/ContextMenu"; +import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu'; import { EventType } from "matrix-js-sdk/src/@types/event"; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ReadPinsEventId } from "../right_panel/PinnedMessagesCard"; @@ -257,55 +257,68 @@ export default class MessageContextMenu extends React.Component { let externalURLButton; let quoteButton; let collapseReplyThread; + let redactItemList; // status is SENT before remote-echo, null after const isSent = !eventStatus || eventStatus === EventStatus.SENT; if (!mxEvent.isRedacted()) { if (unsentReactionsCount !== 0) { resendReactionsButton = ( - - { _t('Resend %(unsentCount)s reaction(s)', {unsentCount: unsentReactionsCount}) } - + ); } } if (isSent && this.state.canRedact) { redactButton = ( - - { _t('Remove') } - + ); } if (isContentActionable(mxEvent)) { forwardButton = ( - - { _t('Forward Message') } - + ); if (this.state.canPin) { pinButton = ( - - { this._isPinned() ? _t('Unpin Message') : _t('Pin Message') } - + ); } } const viewSourceButton = ( - - { _t('View Source') } - + ); if (this.props.eventTileOps) { if (this.props.eventTileOps.isWidgetHidden()) { unhidePreviewButton = ( - - { _t('Unhide Preview') } - + ); } } @@ -316,77 +329,97 @@ export default class MessageContextMenu extends React.Component { } // XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID) const permalinkButton = ( - - { mxEvent.isRedacted() || mxEvent.getType() !== 'm.room.message' - ? _t('Share Permalink') : _t('Share Message') } - + /> ); if (this.props.eventTileOps) { // this event is rendered using TextualBody quoteButton = ( - - { _t('Quote') } - + ); } // Bridges can provide a 'external_url' to link back to the source. - if ( - typeof(mxEvent.event.content.external_url) === "string" && + if (typeof (mxEvent.event.content.external_url) === "string" && isUrlPermitted(mxEvent.event.content.external_url) ) { externalURLButton = ( - - { _t('Source URL') } - + /> ); } if (this.props.collapseReplyThread) { collapseReplyThread = ( - - { _t('Collapse Reply Thread') } - + ); } let reportEventButton; if (mxEvent.getSender() !== me) { reportEventButton = ( - - { _t('Report Content') } - + + ); + } + + const commonItemsList = ( + + { quoteButton } + { forwardButton } + { pinButton } + { permalinkButton } + { reportEventButton } + { externalURLButton } + { unhidePreviewButton } + { viewSourceButton } + { resendReactionsButton } + { collapseReplyThread } + + ); + + if (redactButton) { + redactItemList = ( + + { redactButton } + ); } return ( -
- { resendReactionsButton } - { redactButton } - { forwardButton } - { pinButton } - { viewSourceButton } - { unhidePreviewButton } - { permalinkButton } - { quoteButton } - { externalURLButton } - { collapseReplyThread } - { reportEventButton } -
+ + { commonItemsList } + { redactItemList } + ); } } diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index 37737519ce..3d434e0ee2 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -48,15 +48,14 @@ const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFo const replyThread = getReplyThread && getReplyThread(); const buttonRect = button.current.getBoundingClientRect(); - contextMenu = - - ; + contextMenu = ; } return diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index bfca730776..434656badf 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2524,14 +2524,12 @@ "Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?", "Unable to reject invite": "Unable to reject invite", "Resend %(unsentCount)s reaction(s)": "Resend %(unsentCount)s reaction(s)", - "Forward Message": "Forward Message", - "Unpin Message": "Unpin Message", - "Pin Message": "Pin Message", - "Unhide Preview": "Unhide Preview", - "Share Permalink": "Share Permalink", - "Share Message": "Share Message", + "Forward": "Forward", + "View source": "View source", + "Show preview": "Show preview", "Source URL": "Source URL", - "Collapse Reply Thread": "Collapse Reply Thread", + "Collapse reply thread": "Collapse reply thread", + "Report": "Report", "Clear status": "Clear status", "Update status": "Update status", "Set status": "Set status",