From 3af0138e9d1ee380bea09e8a837ffe718443c09b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 13 May 2021 10:28:35 +0100 Subject: [PATCH 1/6] Update emoji icons to new style --- res/css/views/messages/_MessageActionBar.scss | 1 + res/img/element-icons/room/composer/emoji.svg | 10 +++++----- res/img/element-icons/room/message-bar/emoji.svg | 6 ++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss index 3ecbef0d1f..d41ac3a4ba 100644 --- a/res/css/views/messages/_MessageActionBar.scss +++ b/res/css/views/messages/_MessageActionBar.scss @@ -85,6 +85,7 @@ limitations under the License. left: 0; height: 100%; width: 100%; + mask-size: 18px; mask-repeat: no-repeat; mask-position: center; background-color: $message-action-bar-fg-color; diff --git a/res/img/element-icons/room/composer/emoji.svg b/res/img/element-icons/room/composer/emoji.svg index 9613d9edd9..b02cb69364 100644 --- a/res/img/element-icons/room/composer/emoji.svg +++ b/res/img/element-icons/room/composer/emoji.svg @@ -1,7 +1,7 @@ - - - - - + + + + + diff --git a/res/img/element-icons/room/message-bar/emoji.svg b/res/img/element-icons/room/message-bar/emoji.svg index 697f656b8a..07fee5b834 100644 --- a/res/img/element-icons/room/message-bar/emoji.svg +++ b/res/img/element-icons/room/message-bar/emoji.svg @@ -1,5 +1,3 @@ - - - - + + From b5fa4d88bf5005b5d45bf25ce2207eb570301e17 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 13 May 2021 10:56:51 +0100 Subject: [PATCH 2/6] Add extra add reactions button to encourage more diverse reactions to content --- res/css/views/messages/_ReactionsRow.scss | 20 ++++++++++ src/components/views/messages/ReactionsRow.js | 40 ++++++++++++++++++- src/i18n/strings/en_EN.json | 1 + 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/res/css/views/messages/_ReactionsRow.scss b/res/css/views/messages/_ReactionsRow.scss index 2f5695e1fb..e86d23dc7c 100644 --- a/res/css/views/messages/_ReactionsRow.scss +++ b/res/css/views/messages/_ReactionsRow.scss @@ -17,6 +17,26 @@ limitations under the License. .mx_ReactionsRow { margin: 6px 0; color: $primary-fg-color; + + .mx_ReactionsRow_addReactionButton { + position: relative; + display: inline-block; + width: 16px; + height: 16px; + vertical-align: sub; + + &::before { + content: ''; + position: absolute; + height: 100%; + width: 100%; + mask-size: cover; + mask-repeat: no-repeat; + mask-position: center; + background-color: $tertiary-fg-color; + mask-image: url('$(res)/img/element-icons/room/message-bar/emoji.svg'); + } + } } .mx_ReactionsRow_showAll { diff --git a/src/components/views/messages/ReactionsRow.js b/src/components/views/messages/ReactionsRow.js index d5c8ea2ac9..22f12709a7 100644 --- a/src/components/views/messages/ReactionsRow.js +++ b/src/components/views/messages/ReactionsRow.js @@ -16,16 +16,44 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; +import { EventType } from "matrix-js-sdk/src/@types/event"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { isContentActionable } from '../../../utils/EventUtils'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {replaceableComponent} from "../../../utils/replaceableComponent"; +import {ContextMenuTooltipButton} from "../../../accessibility/context_menu/ContextMenuTooltipButton"; +import {aboveLeftOf, ContextMenu, useContextMenu} from "../../structures/ContextMenu"; // The maximum number of reactions to initially show on a message. const MAX_ITEMS_WHEN_LIMITED = 8; +const ReactButton = ({ mxEvent, reactions }) => { + const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); + + let contextMenu; + if (menuDisplayed) { + const buttonRect = button.current.getBoundingClientRect(); + const ReactionPicker = sdk.getComponent('emojipicker.ReactionPicker'); + contextMenu = + + ; + } + + return + + + { contextMenu } + ; +}; + @replaceableComponent("views.messages.ReactionsRow") export default class ReactionsRow extends React.PureComponent { static propTypes = { @@ -151,13 +179,21 @@ export default class ReactionsRow extends React.PureComponent { ; } + const cli = MatrixClientPeg.get(); + + let addReactionButton; + if (cli.getRoom(mxEvent.getRoomId()).currentState.maySendEvent(EventType.Reaction, cli.getUserId())) { + addReactionButton = ; + } + return
- {items} - {showAllButton} + { items } + { addReactionButton } + { showAllButton }
; } } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index dbe712c691..b9e52a8356 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1864,6 +1864,7 @@ "You sent a verification request": "You sent a verification request", "Error decrypting video": "Error decrypting video", "Error processing voice message": "Error processing voice message", + "Add reaction": "Add reaction", "Show all": "Show all", "Reactions": "Reactions", " reacted with %(content)s": " reacted with %(content)s", From 36633ec025c16bb1fb11a513deab08970770dafa Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 13 May 2021 13:32:38 +0100 Subject: [PATCH 3/6] Tweak alignment of reactions row, move add reaction to right and only show on hover --- res/css/views/messages/_ReactionsRow.scss | 11 ++++++++--- res/css/views/messages/_ReactionsRowButton.scss | 5 +++-- src/components/views/messages/ReactionsRow.js | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/res/css/views/messages/_ReactionsRow.scss b/res/css/views/messages/_ReactionsRow.scss index e86d23dc7c..15d251bd68 100644 --- a/res/css/views/messages/_ReactionsRow.scss +++ b/res/css/views/messages/_ReactionsRow.scss @@ -20,10 +20,11 @@ limitations under the License. .mx_ReactionsRow_addReactionButton { position: relative; - display: inline-block; + display: none; width: 16px; height: 16px; - vertical-align: sub; + vertical-align: middle; + margin-left: 6px; &::before { content: ''; @@ -39,12 +40,16 @@ limitations under the License. } } +.mx_EventTile:hover .mx_ReactionsRow_addReactionButton { + display: inline-block; +} + .mx_ReactionsRow_showAll { text-decoration: none; font-size: $font-10px; font-weight: 600; margin-left: 6px; - vertical-align: top; + vertical-align: middle; &:hover, &:link, diff --git a/res/css/views/messages/_ReactionsRowButton.scss b/res/css/views/messages/_ReactionsRowButton.scss index c132fa5a0f..766fea2f8f 100644 --- a/res/css/views/messages/_ReactionsRowButton.scss +++ b/res/css/views/messages/_ReactionsRowButton.scss @@ -16,14 +16,15 @@ limitations under the License. .mx_ReactionsRowButton { display: inline-flex; - line-height: $font-21px; + line-height: $font-20px; margin-right: 6px; - padding: 0 6px; + padding: 1px 6px; border: 1px solid $reaction-row-button-border-color; border-radius: 10px; background-color: $reaction-row-button-bg-color; cursor: pointer; user-select: none; + vertical-align: middle; &:hover { border-color: $reaction-row-button-hover-border-color; diff --git a/src/components/views/messages/ReactionsRow.js b/src/components/views/messages/ReactionsRow.js index 22f12709a7..2a67519d6b 100644 --- a/src/components/views/messages/ReactionsRow.js +++ b/src/components/views/messages/ReactionsRow.js @@ -192,8 +192,8 @@ export default class ReactionsRow extends React.PureComponent { aria-label={_t("Reactions")} > { items } - { addReactionButton } { showAllButton } + { addReactionButton } ; } } From 87ae47bd6114d660735bba82a71c4fc0883b5314 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 13 May 2021 13:59:10 +0100 Subject: [PATCH 4/6] tweak reactions row some more, third try lucky --- res/css/views/messages/_ReactionsRow.scss | 36 ++++++++++++------- src/components/views/messages/ReactionsRow.js | 5 ++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/res/css/views/messages/_ReactionsRow.scss b/res/css/views/messages/_ReactionsRow.scss index 15d251bd68..f1c19f45a9 100644 --- a/res/css/views/messages/_ReactionsRow.scss +++ b/res/css/views/messages/_ReactionsRow.scss @@ -20,23 +20,33 @@ limitations under the License. .mx_ReactionsRow_addReactionButton { position: relative; - display: none; - width: 16px; - height: 16px; + display: none; // show on hover of the .mx_EventTile + width: 24px; + height: 24px; vertical-align: middle; - margin-left: 6px; + margin-left: 4px; &::before { content: ''; position: absolute; height: 100%; width: 100%; - mask-size: cover; + mask-size: 16px; mask-repeat: no-repeat; mask-position: center; background-color: $tertiary-fg-color; mask-image: url('$(res)/img/element-icons/room/message-bar/emoji.svg'); } + + &.mx_ReactionsRow_addReactionButton_active { + display: inline-block; // keep showing whilst the context menu is shown + } + + &:hover, &.mx_ReactionsRow_addReactionButton_active { + &::before { + background-color: $primary-fg-color; + } + } } } @@ -46,14 +56,16 @@ limitations under the License. .mx_ReactionsRow_showAll { text-decoration: none; - font-size: $font-10px; - font-weight: 600; - margin-left: 6px; + font-size: $font-12px; + line-height: $font-20px; + margin-left: 4px; vertical-align: middle; - &:hover, - &:link, - &:visited { - color: $accent-color; + &:link, &:visited { + color: $tertiary-fg-color + } + + &:hover { + color: $primary-fg-color; } } diff --git a/src/components/views/messages/ReactionsRow.js b/src/components/views/messages/ReactionsRow.js index 2a67519d6b..a7997c0e32 100644 --- a/src/components/views/messages/ReactionsRow.js +++ b/src/components/views/messages/ReactionsRow.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import { EventType } from "matrix-js-sdk/src/@types/event"; +import classNames from "classnames"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; @@ -43,7 +44,9 @@ const ReactButton = ({ mxEvent, reactions }) => { return Date: Thu, 13 May 2021 14:13:00 +0100 Subject: [PATCH 5/6] Convert to Typescript and move from ClientPeg to Context --- res/css/views/messages/_ReactionsRow.scss | 2 +- .../{ReactionsRow.js => ReactionsRow.tsx} | 55 ++++++++------- ...onsRowButton.js => ReactionsRowButton.tsx} | 70 ++++++++++--------- ...oltip.js => ReactionsRowButtonTooltip.tsx} | 37 +++++----- 4 files changed, 87 insertions(+), 77 deletions(-) rename src/components/views/messages/{ReactionsRow.js => ReactionsRow.tsx} (82%) rename src/components/views/messages/{ReactionsRowButton.js => ReactionsRowButton.tsx} (73%) rename src/components/views/messages/{ReactionsRowButtonTooltip.js => ReactionsRowButtonTooltip.tsx} (74%) diff --git a/res/css/views/messages/_ReactionsRow.scss b/res/css/views/messages/_ReactionsRow.scss index f1c19f45a9..244439bf74 100644 --- a/res/css/views/messages/_ReactionsRow.scss +++ b/res/css/views/messages/_ReactionsRow.scss @@ -62,7 +62,7 @@ limitations under the License. vertical-align: middle; &:link, &:visited { - color: $tertiary-fg-color + color: $tertiary-fg-color; } &:hover { diff --git a/src/components/views/messages/ReactionsRow.js b/src/components/views/messages/ReactionsRow.tsx similarity index 82% rename from src/components/views/messages/ReactionsRow.js rename to src/components/views/messages/ReactionsRow.tsx index a7997c0e32..e1fcbe5364 100644 --- a/src/components/views/messages/ReactionsRow.js +++ b/src/components/views/messages/ReactionsRow.tsx @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd +Copyright 2019, 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,29 +14,30 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { EventType } from "matrix-js-sdk/src/@types/event"; +import React from "react"; import classNames from "classnames"; +import { EventType } from "matrix-js-sdk/src/@types/event"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { Relations } from "matrix-js-sdk/src/models/relations"; -import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { isContentActionable } from '../../../utils/EventUtils'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {ContextMenuTooltipButton} from "../../../accessibility/context_menu/ContextMenuTooltipButton"; -import {aboveLeftOf, ContextMenu, useContextMenu} from "../../structures/ContextMenu"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton"; +import { aboveLeftOf, ContextMenu, useContextMenu } from "../../structures/ContextMenu"; +import ReactionPicker from "../emojipicker/ReactionPicker"; +import ReactionsRowButton from "./ReactionsRowButton"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; // The maximum number of reactions to initially show on a message. const MAX_ITEMS_WHEN_LIMITED = 8; -const ReactButton = ({ mxEvent, reactions }) => { +const ReactButton = ({ mxEvent, reactions }: IProps) => { const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); let contextMenu; if (menuDisplayed) { const buttonRect = button.current.getBoundingClientRect(); - const ReactionPicker = sdk.getComponent('emojipicker.ReactionPicker'); contextMenu = ; @@ -57,17 +58,24 @@ const ReactButton = ({ mxEvent, reactions }) => { ; }; -@replaceableComponent("views.messages.ReactionsRow") -export default class ReactionsRow extends React.PureComponent { - static propTypes = { - // The event we're displaying reactions for - mxEvent: PropTypes.object.isRequired, - // The Relations model from the JS SDK for reactions to `mxEvent` - reactions: PropTypes.object, - } +interface IProps { + // The event we're displaying reactions for + mxEvent: MatrixEvent; + // The Relations model from the JS SDK for reactions to `mxEvent` + reactions?: Relations; +} - constructor(props) { - super(props); +interface IState { + myReactions: MatrixEvent[]; + showAll: boolean; +} + +@replaceableComponent("views.messages.ReactionsRow") +export default class ReactionsRow extends React.PureComponent { + static contextType = MatrixClientContext; + + constructor(props, context) { + super(props, context); if (props.reactions) { props.reactions.on("Relations.add", this.onReactionsChange); @@ -123,7 +131,7 @@ export default class ReactionsRow extends React.PureComponent { if (!reactions) { return null; } - const userId = MatrixClientPeg.get().getUserId(); + const userId = this.context.getUserId(); const myReactions = reactions.getAnnotationsBySender()[userId]; if (!myReactions) { return null; @@ -145,7 +153,6 @@ export default class ReactionsRow extends React.PureComponent { return null; } - const ReactionsRowButton = sdk.getComponent('messages.ReactionsRowButton'); let items = reactions.getSortedAnnotationsByKey().map(([content, events]) => { const count = events.size; if (!count) { @@ -182,7 +189,7 @@ export default class ReactionsRow extends React.PureComponent { ; } - const cli = MatrixClientPeg.get(); + const cli = this.context; let addReactionButton; if (cli.getRoom(mxEvent.getRoomId()).currentState.maySendEvent(EventType.Reaction, cli.getUserId())) { diff --git a/src/components/views/messages/ReactionsRowButton.js b/src/components/views/messages/ReactionsRowButton.tsx similarity index 73% rename from src/components/views/messages/ReactionsRowButton.js rename to src/components/views/messages/ReactionsRowButton.tsx index b37a949e57..393c6bca88 100644 --- a/src/components/views/messages/ReactionsRowButton.js +++ b/src/components/views/messages/ReactionsRowButton.tsx @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd +Copyright 2019, 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,49 +14,54 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; +import React from "react"; +import classNames from "classnames"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; -import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; import dis from "../../../dispatcher/dispatcher"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import ReactionsRowButtonTooltip from "./ReactionsRowButtonTooltip"; +import AccessibleButton from "../elements/AccessibleButton"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; + +interface IProps { + // The event we're displaying reactions for + mxEvent: MatrixEvent; + // The reaction content / key / emoji + content: string; + // The count of votes for this key + count: number; + // A Set of Martix reaction events for this key + reactionEvents: Set; + // A possible Matrix event if the current user has voted for this type + myReactionEvent?: MatrixEvent; +} + +interface IState { + tooltipRendered: boolean; + tooltipVisible: boolean; +} @replaceableComponent("views.messages.ReactionsRowButton") -export default class ReactionsRowButton extends React.PureComponent { - static propTypes = { - // The event we're displaying reactions for - mxEvent: PropTypes.object.isRequired, - // The reaction content / key / emoji - content: PropTypes.string.isRequired, - // The count of votes for this key - count: PropTypes.number.isRequired, - // A Set of Martix reaction events for this key - reactionEvents: PropTypes.object.isRequired, - // A possible Matrix event if the current user has voted for this type - myReactionEvent: PropTypes.object, - } +export default class ReactionsRowButton extends React.PureComponent { + static contextType = MatrixClientContext; - constructor(props) { - super(props); + state = { + tooltipRendered: false, + tooltipVisible: false, + }; - this.state = { - tooltipVisible: false, - }; - } - - onClick = (ev) => { + onClick = () => { const { mxEvent, myReactionEvent, content } = this.props; if (myReactionEvent) { - MatrixClientPeg.get().redactEvent( + this.context.redactEvent( mxEvent.getRoomId(), myReactionEvent.getId(), ); } else { - MatrixClientPeg.get().sendEvent(mxEvent.getRoomId(), "m.reaction", { + this.context.sendEvent(mxEvent.getRoomId(), "m.reaction", { "m.relates_to": { "rel_type": "m.annotation", "event_id": mxEvent.getId(), @@ -83,8 +88,6 @@ export default class ReactionsRowButton extends React.PureComponent { } render() { - const ReactionsRowButtonTooltip = - sdk.getComponent('messages.ReactionsRowButtonTooltip'); const { mxEvent, content, count, reactionEvents, myReactionEvent } = this.props; const classes = classNames({ @@ -102,7 +105,7 @@ export default class ReactionsRowButton extends React.PureComponent { />; } - const room = MatrixClientPeg.get().getRoom(mxEvent.getRoomId()); + const room = this.context.getRoom(mxEvent.getRoomId()); let label; if (room) { const senders = []; @@ -130,7 +133,6 @@ export default class ReactionsRowButton extends React.PureComponent { ); } const isPeeking = room.getMyMembership() !== "join"; - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); return ; + visible: boolean; +} @replaceableComponent("views.messages.ReactionsRowButtonTooltip") -export default class ReactionsRowButtonTooltip extends React.PureComponent { - static propTypes = { - // The event we're displaying reactions for - mxEvent: PropTypes.object.isRequired, - // The reaction content / key / emoji - content: PropTypes.string.isRequired, - // A Set of Martix reaction events for this key - reactionEvents: PropTypes.object.isRequired, - visible: PropTypes.bool.isRequired, - } +export default class ReactionsRowButtonTooltip extends React.PureComponent { + static contextType = MatrixClientContext; render() { - const Tooltip = sdk.getComponent('elements.Tooltip'); const { content, reactionEvents, mxEvent, visible } = this.props; - const room = MatrixClientPeg.get().getRoom(mxEvent.getRoomId()); + const room = this.context.getRoom(mxEvent.getRoomId()); let tooltipLabel; if (room) { const senders = []; From a41d76b588cd619a17770102457dbc57243e1e2f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 13 May 2021 14:14:01 +0100 Subject: [PATCH 6/6] fix typos --- src/components/views/messages/ReactionsRowButton.tsx | 2 +- src/components/views/messages/ReactionsRowButtonTooltip.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/messages/ReactionsRowButton.tsx b/src/components/views/messages/ReactionsRowButton.tsx index 393c6bca88..d163f1ad30 100644 --- a/src/components/views/messages/ReactionsRowButton.tsx +++ b/src/components/views/messages/ReactionsRowButton.tsx @@ -33,7 +33,7 @@ interface IProps { content: string; // The count of votes for this key count: number; - // A Set of Martix reaction events for this key + // A Set of Matrix reaction events for this key reactionEvents: Set; // A possible Matrix event if the current user has voted for this type myReactionEvent?: MatrixEvent; diff --git a/src/components/views/messages/ReactionsRowButtonTooltip.tsx b/src/components/views/messages/ReactionsRowButtonTooltip.tsx index d9e8a45b28..e60174530a 100644 --- a/src/components/views/messages/ReactionsRowButtonTooltip.tsx +++ b/src/components/views/messages/ReactionsRowButtonTooltip.tsx @@ -29,7 +29,7 @@ interface IProps { mxEvent: MatrixEvent; // The reaction content / key / emoji content: string; - // A Set of Martix reaction events for this key + // A Set of Matrix reaction events for this key reactionEvents: Set; visible: boolean; }