diff --git a/css/_reactions.scss b/css/_reactions.scss new file mode 100644 index 000000000..c531e6d32 --- /dev/null +++ b/css/_reactions.scss @@ -0,0 +1,20 @@ +.reactions-dialog { + .reactions-dialog-title { + margin-bottom: 10px; + } + + .reactions-dialog-contents { + align-items: center; + display: flex; + flex-direction: row; + flex-wrap: wrap; + padding: 10px; + min-width: 250px; + } + + .reactions-dialog-cell { + display: inline; + height: 50px; + width: 50px; + } +} diff --git a/css/main.scss b/css/main.scss index 3d78bb622..1ead560dc 100644 --- a/css/main.scss +++ b/css/main.scss @@ -75,5 +75,6 @@ @import 'unsupported-browser/main'; @import 'modals/invite/add-people'; @import 'vertical_filmstrip_overrides'; +@import 'reactions'; /* Modules END */ diff --git a/interface_config.js b/interface_config.js index 38fbef8e6..6f6b4914c 100644 --- a/interface_config.js +++ b/interface_config.js @@ -43,7 +43,7 @@ var interfaceConfig = { 'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup', // extended toolbar - 'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'filmstrip' ], + 'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'reactions', 'filmstrip' ], /** * Main Toolbar Buttons diff --git a/react/features/reactions/components/ReactionsDialog.web.js b/react/features/reactions/components/ReactionsDialog.web.js new file mode 100644 index 000000000..01b2cca9e --- /dev/null +++ b/react/features/reactions/components/ReactionsDialog.web.js @@ -0,0 +1,78 @@ +// @flow + +import React, { Component } from 'react'; + +type Props = { + onClose: Function +}; + +/** + * The list of supported reactions (i.e. reaction buttons). + */ +const REACTIONS = [ +]; + +// FIXME Pretend there's a list of supported reactions (i.e. reaction buttons). +for (let i = 1; i < 21; ++i) { + REACTIONS.push(`smiley${i}`); +} + +/** + * Represents the dialog in the terms of {@link ToolbarButtonWithDialog} which + * renders the list of supported reactions (i.e. reaction buttons). + */ +export default class ReactionsDialog extends Component { + /** + * Implements React's {@link Component#render()}. + * + * @inheritdoc + * @returns {React$Element} + */ + render() { + return ( +
+

+ Reactions +

+
+ { this._renderContents() } +
+
+ ); + } + + /** + * Handles the click on a reaction (button). + * + * @param {*} reaction - The reaction (button) which was clicked. + * @returns {void} + */ + _onClick(reaction) { // eslint-disable-line no-unused-vars + // Close this ReactionsDialog. + this.props.onClose(); + } + + /** + * Renders the contents of this ReactionsDialog minus its title. + * + * @returns {React$Node} + */ + _renderContents() { + const contents = []; + + for (const reaction of REACTIONS) { + /* eslint-disable react/jsx-no-bind */ + + contents.push( + + ); + + /* eslint-enable react/jsx-no-bind */ + } + + return contents; + } +} diff --git a/react/features/reactions/components/ReactionsToolbarButton.web.js b/react/features/reactions/components/ReactionsToolbarButton.web.js new file mode 100644 index 000000000..48abd8839 --- /dev/null +++ b/react/features/reactions/components/ReactionsToolbarButton.web.js @@ -0,0 +1,45 @@ +// @flow + +import React, { Component } from 'react'; + +import { ToolbarButtonWithDialog } from '../../toolbox'; + +import ReactionsDialog from './ReactionsDialog'; + +type Props = { + tooltipPosition: * +}; + +/** + * The {@code ToolbarButton} configuration which describes how + * {@link ReactionsToolbarButton} is to be rendered (by default). + * + * @type {object} + */ +const DEFAULT_BUTTON_CONFIGURATION = { + buttonName: 'reactions', + classNames: [ 'button', 'icon-star-full' ], + enabled: true, + id: 'toolbar_button_reactions' +}; + +/** + * Implements the Web {@code ToolbarButton} which shows the dialog with the list + * of supported reactions (i.e. reaction buttons). + */ +export default class ReactionsToolbarButton extends Component { + /** + * Implements React's {@link Component#render()}. + * + * @inheritdoc + * @returns {ReactElement} + */ + render() { + return ( + + ); + } +} diff --git a/react/features/reactions/components/index.js b/react/features/reactions/components/index.js new file mode 100644 index 000000000..eb7b8d570 --- /dev/null +++ b/react/features/reactions/components/index.js @@ -0,0 +1 @@ +export { default as ReactionsToolbarButton } from './ReactionsToolbarButton'; diff --git a/react/features/reactions/index.js b/react/features/reactions/index.js new file mode 100644 index 000000000..07635cbbc --- /dev/null +++ b/react/features/reactions/index.js @@ -0,0 +1 @@ +export * from './components'; diff --git a/react/features/toolbox/defaultToolbarButtons.web.js b/react/features/toolbox/defaultToolbarButtons.web.js index e3b95e0d8..5f97f00fc 100644 --- a/react/features/toolbox/defaultToolbarButtons.web.js +++ b/react/features/toolbox/defaultToolbarButtons.web.js @@ -13,6 +13,7 @@ import { import { ParticipantCounter } from '../contact-list'; import { openDeviceSelectionDialog } from '../device-selection'; import { InfoDialogButton, openInviteDialog } from '../invite'; +import { ReactionsToolbarButton } from '../reactions'; import UIEvents from '../../../service/UI/UIEvents'; import { VideoQualityButton } from '../video-quality'; @@ -435,6 +436,10 @@ export default function getDefaultButtons() { tooltipKey: 'toolbar.raiseHand' }, + reactions: { + component: ReactionsToolbarButton + }, + /** * The descriptor of the recording toolbar button. Requires additional * initialization in the recording module. diff --git a/react/features/toolbox/functions.web.js b/react/features/toolbox/functions.web.js index f055e4919..ae2ea83c4 100644 --- a/react/features/toolbox/functions.web.js +++ b/react/features/toolbox/functions.web.js @@ -25,6 +25,17 @@ export function getDefaultToolboxButtons(buttonHandlers: Object): Object { if (typeof interfaceConfig !== 'undefined' && interfaceConfig.TOOLBAR_BUTTONS) { + // FIXME Force (the display of) specific toolbar buttons in order to + // avoid the necessity to have them in interfaceConfig. + const FORCED_TOOLBAR_BUTTONS = [ + 'reactions' + ]; + + for (const forced of FORCED_TOOLBAR_BUTTONS) { + if (interfaceConfig.TOOLBAR_BUTTONS.indexOf(forced) === -1) { + interfaceConfig.TOOLBAR_BUTTONS.push(forced); + } + } toolbarButtons = interfaceConfig.TOOLBAR_BUTTONS.reduce( diff --git a/react/features/video-quality/components/VideoQualityButton.web.js b/react/features/video-quality/components/VideoQualityButton.web.js index f985db09d..d6e1d2539 100644 --- a/react/features/video-quality/components/VideoQualityButton.web.js +++ b/react/features/video-quality/components/VideoQualityButton.web.js @@ -25,7 +25,7 @@ const DEFAULT_BUTTON_CONFIGURATION = { * * @extends Component */ -class VideoQualityButton extends Component { +export default class VideoQualityButton extends Component { /** * {@code VideoQualityButton}'s property types. * @@ -54,5 +54,3 @@ class VideoQualityButton extends Component { ); } } - -export default VideoQualityButton;