feat(reactions): port new reactions and fix emojiRain
This commit is contained in:
parent
6a10a27f2a
commit
f575ecd4c8
@ -4,11 +4,14 @@ import PropTypes from 'prop-types';
|
||||
import BBBMenu from '/imports/ui/components/common/menu/component';
|
||||
import UserReactionService from '/imports/ui/components/user-reaction/service';
|
||||
import UserListService from '/imports/ui/components/user-list/service';
|
||||
import { Emoji } from 'emoji-mart';
|
||||
import { convertRemToPixels } from '/imports/utils/dom-utils';
|
||||
import data from '@emoji-mart/data';
|
||||
import { init } from 'emoji-mart';
|
||||
|
||||
import Styled from './styles';
|
||||
|
||||
const REACTIONS = Meteor.settings.public.userReaction.reactions;
|
||||
|
||||
const ReactionsButton = (props) => {
|
||||
const {
|
||||
intl,
|
||||
@ -20,6 +23,9 @@ const ReactionsButton = (props) => {
|
||||
autoCloseReactionsBar,
|
||||
} = props;
|
||||
|
||||
// initialize emoji-mart data, need for the new version
|
||||
init({ data });
|
||||
|
||||
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
@ -74,43 +80,20 @@ const ReactionsButton = (props) => {
|
||||
};
|
||||
|
||||
const emojiProps = {
|
||||
native: true,
|
||||
size: convertRemToPixels(1.5),
|
||||
padding: '4px',
|
||||
};
|
||||
|
||||
const reactions = [
|
||||
{
|
||||
id: 'smiley',
|
||||
native: '😃',
|
||||
},
|
||||
{
|
||||
id: 'neutral_face',
|
||||
native: '😐',
|
||||
},
|
||||
{
|
||||
id: 'slightly_frowning_face',
|
||||
native: '🙁',
|
||||
},
|
||||
{
|
||||
id: '+1',
|
||||
native: '👍',
|
||||
},
|
||||
{
|
||||
id: '-1',
|
||||
native: '👎',
|
||||
},
|
||||
{
|
||||
id: 'clap',
|
||||
native: '👏',
|
||||
},
|
||||
];
|
||||
const handReaction = {
|
||||
id: 'hand',
|
||||
native: '✋',
|
||||
};
|
||||
|
||||
let actions = [];
|
||||
|
||||
reactions.forEach(({ id, native }) => {
|
||||
REACTIONS.forEach(({ id, native }) => {
|
||||
actions.push({
|
||||
label: <Styled.ButtonWrapper active={currentUserReaction === native}><Emoji key={id} emoji={{ id }} {...emojiProps} /></Styled.ButtonWrapper>,
|
||||
label: <Styled.ButtonWrapper active={currentUserReaction === native}><em-emoji key={native} native={native} {...emojiProps} /></Styled.ButtonWrapper>,
|
||||
key: id,
|
||||
onClick: () => handleReactionSelect(native),
|
||||
customStyles: actionCustomStyles,
|
||||
@ -118,29 +101,29 @@ const ReactionsButton = (props) => {
|
||||
});
|
||||
|
||||
actions.push({
|
||||
label: <Styled.RaiseHandButtonWrapper isMobile={isMobile} data-test={raiseHand ? 'lowerHandBtn' : 'raiseHandBtn'} active={raiseHand}><Emoji key="hand" emoji={{ id: 'hand' }} {...emojiProps} />{RaiseHandButtonLabel()}</Styled.RaiseHandButtonWrapper>,
|
||||
label: <Styled.RaiseHandButtonWrapper isMobile={isMobile} data-test={raiseHand ? 'lowerHandBtn' : 'raiseHandBtn'} active={raiseHand}><em-emoji key={handReaction.id} native={handReaction.native} emoji={{ id: handReaction.id }} {...emojiProps} />{RaiseHandButtonLabel()}</Styled.RaiseHandButtonWrapper>,
|
||||
key: 'hand',
|
||||
onClick: () => handleRaiseHandButtonClick(),
|
||||
customStyles: {...actionCustomStyles, width: 'auto'},
|
||||
});
|
||||
|
||||
const icon = !raiseHand && currentUserReaction === 'none' ? 'hand' : null;
|
||||
const currentUserReactionEmoji = reactions.find(({ native }) => native === currentUserReaction);
|
||||
const currentUserReactionEmoji = REACTIONS.find(({ native }) => native === currentUserReaction);
|
||||
|
||||
let customIcon = null;
|
||||
|
||||
if (raiseHand) {
|
||||
customIcon = <Emoji key="hand" emoji={{ id: 'hand' }} {...emojiProps} />;
|
||||
customIcon = <em-emoji key={handReaction.id} native={handReaction.native} emoji={handReaction} {...emojiProps} />;
|
||||
} else {
|
||||
if (!icon) {
|
||||
customIcon = <Emoji key={currentUserReactionEmoji?.id} emoji={{ id: currentUserReactionEmoji?.id }} {...emojiProps} />;
|
||||
customIcon = <em-emoji key={currentUserReactionEmoji?.id} native={currentUserReactionEmoji?.native} emoji={{ id: currentUserReactionEmoji?.id }} {...emojiProps} />;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<BBBMenu
|
||||
trigger={(
|
||||
<Styled.ReactionsDropdown>
|
||||
<Styled.ReactionsDropdown id="interactionsButton">
|
||||
<Styled.RaiseHandButton
|
||||
data-test="reactionsButton"
|
||||
icon={icon}
|
||||
|
@ -101,28 +101,13 @@ const ReactionsDropdown = styled.div`
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
.emoji-mart-bar {
|
||||
display: none;
|
||||
}
|
||||
.emoji-mart-search {
|
||||
display: none;
|
||||
}
|
||||
.emoji-mart-category[aria-label="Frequently Used"] {
|
||||
display: none;
|
||||
}
|
||||
.emoji-mart-category-label{
|
||||
display: none;
|
||||
}
|
||||
.emoji-mart{
|
||||
border: none;
|
||||
}
|
||||
@media(min-width: 600px) {
|
||||
.emoji-mart-scroll{
|
||||
overflow:hidden;
|
||||
padding: 0;
|
||||
height: 270px;
|
||||
width: 280px;
|
||||
}
|
||||
overflow: hidden;
|
||||
margin: 0.2em 0.2em 0.2em 0.2em;
|
||||
text-align: center;
|
||||
max-height: 270px;
|
||||
width: 270px;
|
||||
em-emoji {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -29,6 +29,7 @@ import WebcamContainer from '../webcam/container';
|
||||
import PresentationAreaContainer from '../presentation/presentation-area/container';
|
||||
import ScreenshareContainer from '../screenshare/container';
|
||||
import ExternalVideoContainer from '../external-video-player/container';
|
||||
import EmojiRainContainer from '../emoji-rain/container';
|
||||
import Styled from './styles';
|
||||
import { DEVICE_TYPE, ACTIONS, SMALL_VIEWPORT_BREAKPOINT, PANELS } from '../layout/enums';
|
||||
import {
|
||||
@ -660,6 +661,7 @@ class App extends Component {
|
||||
<PadsSessionsContainer />
|
||||
<WakeLockContainer />
|
||||
{this.renderActionsBar()}
|
||||
<EmojiRainContainer />
|
||||
{customStyleUrl ? <link rel="stylesheet" type="text/css" href={customStyleUrl} /> : null}
|
||||
{customStyle ? <link rel="stylesheet" type="text/css" href={`data:text/css;charset=UTF-8,${encodeURIComponent(customStyle)}`} /> : null}
|
||||
{isRandomUserSelectModalOpen ? <RandomUserSelectContainer
|
||||
|
@ -251,7 +251,7 @@ class MessageForm extends PureComponent {
|
||||
stopUserTyping,
|
||||
} = this.props;
|
||||
const { message } = this.state;
|
||||
let msg = message.trim();
|
||||
const msg = message.trim();
|
||||
|
||||
if (msg.length < minMessageLength) return;
|
||||
|
||||
@ -291,8 +291,6 @@ class MessageForm extends PureComponent {
|
||||
<Styled.EmojiPickerWrapper>
|
||||
<Styled.EmojiPicker
|
||||
onEmojiSelect={(emojiObject) => this.handleEmojiSelect(emojiObject)}
|
||||
showPreview={false}
|
||||
showSkinTones={false}
|
||||
/>
|
||||
</Styled.EmojiPickerWrapper>
|
||||
);
|
||||
|
@ -109,21 +109,11 @@ const EmojiButton = styled(Button)`
|
||||
`;
|
||||
|
||||
const EmojiPickerWrapper = styled.div`
|
||||
.emoji-mart {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
.emoji-mart-anchor {
|
||||
cursor: pointer;
|
||||
}
|
||||
.emoji-mart-emoji {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
.emoji-mart-category-list {
|
||||
span {
|
||||
cursor: pointer !important;
|
||||
display: inline-block !important;
|
||||
}
|
||||
em-emoji-picker {
|
||||
width: 100%;
|
||||
max-height: 300px;
|
||||
}
|
||||
padding-bottom: 5px;
|
||||
`;
|
||||
|
||||
const EmojiPicker = styled(EmojiPickerComponent)``;
|
||||
|
@ -1,26 +1,16 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { Picker } from 'emoji-mart';
|
||||
import 'emoji-mart/css/emoji-mart.css';
|
||||
import data from '@emoji-mart/data';
|
||||
import Picker from '@emoji-mart/react';
|
||||
|
||||
const DISABLE_EMOJIS = Meteor.settings.public.chat.disableEmojis;
|
||||
const FREQUENT_SORT_ON_CLICK = Meteor.settings.public.chat.emojiPicker.frequentEmojiSortOnClick;
|
||||
|
||||
const propTypes = {
|
||||
intl: PropTypes.shape({
|
||||
formatMessage: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
onEmojiSelect: PropTypes.func.isRequired,
|
||||
style: PropTypes.shape({}),
|
||||
showPreview: PropTypes.bool,
|
||||
showSkinTones: PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
style: null,
|
||||
showPreview: true,
|
||||
showSkinTones: true,
|
||||
};
|
||||
|
||||
const emojisToExclude = [
|
||||
@ -31,8 +21,6 @@ const EmojiPicker = (props) => {
|
||||
const {
|
||||
intl,
|
||||
onEmojiSelect,
|
||||
showPreview,
|
||||
showSkinTones,
|
||||
} = props;
|
||||
|
||||
const i18n = {
|
||||
@ -65,23 +53,19 @@ const EmojiPicker = (props) => {
|
||||
|
||||
return (
|
||||
<Picker
|
||||
emoji=""
|
||||
onSelect={(emojiObject, event) => onEmojiSelect(emojiObject, event)}
|
||||
enableFrequentEmojiSort={FREQUENT_SORT_ON_CLICK}
|
||||
native
|
||||
title=""
|
||||
data={data}
|
||||
onEmojiSelect={(emojiObject, event) => onEmojiSelect(emojiObject, event)}
|
||||
emojiSize={24}
|
||||
emojiTooltip
|
||||
i18n={i18n}
|
||||
showPreview={showPreview}
|
||||
showSkinTones={showSkinTones}
|
||||
useButton
|
||||
emojisToShowFilter={(emoji) => !emojisToExclude.includes(emoji.unified)}
|
||||
previewPosition="none"
|
||||
skinTonePosition="none"
|
||||
theme="light"
|
||||
dynamicWidth
|
||||
exceptEmojis={emojisToExclude}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
EmojiPicker.propTypes = propTypes;
|
||||
EmojiPicker.defaultProps = defaultProps;
|
||||
|
||||
export default injectIntl(EmojiPicker);
|
@ -1,71 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { Picker } from 'emoji-mart';
|
||||
import 'emoji-mart/css/emoji-mart.css';
|
||||
|
||||
const propTypes = {
|
||||
intl: PropTypes.shape({
|
||||
formatMessage: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
onEmojiSelect: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
};
|
||||
|
||||
const emojisToExclude = [
|
||||
// reactions
|
||||
'1F605', '1F61C', '1F604', '1F609', '1F602', '1F92A',
|
||||
'1F634', '1F62C', '1F633', '1F60D', '02665', '1F499',
|
||||
'1F615', '1F61F', '1F928', '1F644', '1F612', '1F621',
|
||||
'1F614', '1F625', '1F62D', '1F62F', '1F631', '1F630',
|
||||
'1F44F', '1F44C', '1F44D', '1F44E', '1F4AA', '1F44A',
|
||||
'1F64C', '1F64F', '1F440', '1F4A9', '1F921', '1F480',
|
||||
];
|
||||
|
||||
const inlineStyle = {
|
||||
margin: '.5rem 0',
|
||||
alignSelf: 'center',
|
||||
width: '100%',
|
||||
};
|
||||
|
||||
const ReactionsPicker = (props) => {
|
||||
const {
|
||||
intl,
|
||||
onEmojiSelect,
|
||||
style,
|
||||
} = props;
|
||||
|
||||
const i18n = {
|
||||
notfound: intl.formatMessage({ id: 'app.emojiPicker.notFound' }),
|
||||
clear: intl.formatMessage({ id: 'app.emojiPicker.clear' }),
|
||||
skintext: intl.formatMessage({ id: 'app.emojiPicker.skintext' }),
|
||||
categories: {
|
||||
reactions: intl.formatMessage({ id: 'app.emojiPicker.categories.reactions' }),
|
||||
},
|
||||
categorieslabel: intl.formatMessage({ id: 'app.emojiPicker.categories.label' }),
|
||||
};
|
||||
|
||||
return (
|
||||
<Picker
|
||||
onSelect={(emojiObject, event) => onEmojiSelect(emojiObject, event)}
|
||||
native
|
||||
emoji=""
|
||||
title=""
|
||||
emojiSize={30}
|
||||
emojiTooltip
|
||||
style={Object.assign(inlineStyle, style)}
|
||||
i18n={i18n}
|
||||
showPreview={false}
|
||||
showSkinTones={false}
|
||||
emojisToShowFilter={(emoji) => emojisToExclude.includes(emoji.unified)}
|
||||
/>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
ReactionsPicker.propTypes = propTypes;
|
||||
ReactionsPicker.defaultProps = defaultProps;
|
||||
|
||||
export default injectIntl(ReactionsPicker);
|
@ -0,0 +1,35 @@
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
const EmojiWrapper = styled.span`
|
||||
padding-top: 0.9em;
|
||||
padding-bottom: 0.1em;
|
||||
${({ selected }) => !selected && css`
|
||||
:hover {
|
||||
border-radius:100%;
|
||||
outline-color: transparent;
|
||||
outline-style:solid;
|
||||
box-shadow: 0 0 0 0.25em #eee;
|
||||
background-color: #eee;
|
||||
opacity: 0.75;
|
||||
}
|
||||
`}
|
||||
${({ selected }) => selected && css`
|
||||
em-emoji {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
`}
|
||||
${({ selected, emoji }) => selected && selected !== emoji && css`
|
||||
opacity: 0.75;
|
||||
`}
|
||||
${({ selected, emoji }) => selected && selected === emoji && css`
|
||||
border-radius:100%;
|
||||
outline-color: transparent;
|
||||
outline-style:solid;
|
||||
box-shadow: 0 0 0 0.25em #eee;
|
||||
background-color: #eee;
|
||||
`}
|
||||
`;
|
||||
|
||||
export default {
|
||||
EmojiWrapper,
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
.dropdownContent {
|
||||
section[class^="emoji-mart-search"] {
|
||||
display: none !important;
|
||||
}
|
||||
section[class^="emoji-mart emoji-mart-light"] {
|
||||
display: unset;
|
||||
border: unset;
|
||||
}
|
||||
div[class^="emoji-mart-bar"] {
|
||||
display: none !important;
|
||||
}
|
||||
section[aria-label^="Frequently Used"] {
|
||||
display: none !important;
|
||||
}
|
||||
div[class^="emoji-mart-category-label"] {
|
||||
display: none !important;
|
||||
}
|
||||
div[class^="emoji-mart-scroll"] {
|
||||
overflow-y: unset;
|
||||
height: unset;
|
||||
}
|
||||
ul[class^="emoji-mart-category-list"] {
|
||||
span {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import Settings from '/imports/ui/services/settings';
|
||||
import Service from './service';
|
||||
|
||||
const EmojiRain = ({ reactions }) => {
|
||||
const containerRef = useRef(null);
|
||||
const [isAnimating, setIsAnimating] = useState(false);
|
||||
const EMOJI_SIZE = Meteor.settings.public.app.emojiRain.emojiSize;
|
||||
const NUMBER_OF_EMOJIS = Meteor.settings.public.app.emojiRain.numberOfEmojis;
|
||||
const EMOJI_RAIN_ENABLED = Meteor.settings.public.app.emojiRain.enabled;
|
||||
|
||||
const { animations } = Settings.application;
|
||||
|
||||
function createEmojiRain(emoji) {
|
||||
const coord = Service.getInteractionsButtonCoordenates();
|
||||
const flyingEmojis = [];
|
||||
|
||||
for (i = 0; i < NUMBER_OF_EMOJIS; i++) {
|
||||
const initialPosition = {
|
||||
x: coord.x + coord.width / 8,
|
||||
y: coord.y + coord.height / 5,
|
||||
};
|
||||
const endPosition = {
|
||||
x: Math.floor(Math.random() * 100) + coord.x - 100 / 2,
|
||||
y: Math.floor(Math.random() * 300) + coord.y / 2,
|
||||
};
|
||||
const scale = Math.floor(Math.random() * (8 - 4 + 1)) - 40;
|
||||
const sec = Math.floor(Math.random() * 1700) + 2000;
|
||||
|
||||
const shapeElement = document.createElement('svg');
|
||||
const emojiElement = document.createElement('text');
|
||||
emojiElement.setAttribute('x', '50%');
|
||||
emojiElement.setAttribute('y', '50%');
|
||||
emojiElement.innerHTML = emoji;
|
||||
|
||||
shapeElement.style.position = 'absolute';
|
||||
shapeElement.style.left = `${initialPosition.x}px`;
|
||||
shapeElement.style.top = `${initialPosition.y}px`;
|
||||
shapeElement.style.transform = `scaleX(0.${scale}) scaleY(0.${scale})`;
|
||||
shapeElement.style.transition = `${sec}ms`;
|
||||
shapeElement.style.fontSize = `${EMOJI_SIZE}em`;
|
||||
shapeElement.style.pointerEvents = 'none';
|
||||
|
||||
shapeElement.appendChild(emojiElement);
|
||||
containerRef.current.appendChild(shapeElement);
|
||||
|
||||
flyingEmojis.push({ shapeElement, endPosition });
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => setTimeout(() => flyingEmojis.forEach((emoji) => {
|
||||
const { shapeElement, endPosition } = emoji;
|
||||
shapeElement.style.left = `${endPosition.x}px`;
|
||||
shapeElement.style.top = `${endPosition.y}px`;
|
||||
shapeElement.style.transform = 'scaleX(0) scaleY(0)';
|
||||
}), 0));
|
||||
|
||||
setTimeout(() => {
|
||||
flyingEmojis.forEach((emoji) => emoji.shapeElement.remove());
|
||||
flyingEmojis.length = 0;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.hidden) {
|
||||
setIsAnimating(false);
|
||||
} else if (EMOJI_RAIN_ENABLED && animations) {
|
||||
setIsAnimating(true);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (EMOJI_RAIN_ENABLED && animations && !isAnimating && !document.hidden) {
|
||||
setIsAnimating(true);
|
||||
} else if (!animations) {
|
||||
setIsAnimating(false);
|
||||
}
|
||||
}, [EMOJI_RAIN_ENABLED, animations, isAnimating]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAnimating) {
|
||||
reactions.forEach((reaction) => {
|
||||
const currentTime = new Date().getTime();
|
||||
const secondsSinceCreated = (currentTime - reaction.creationDate.getTime()) / 1000;
|
||||
if (secondsSinceCreated <= 1 && (reaction.reaction !== 'none')) {
|
||||
createEmojiRain(reaction.reaction);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [isAnimating, reactions]);
|
||||
|
||||
const containerStyle = {
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
overflow: 'hidden',
|
||||
pointerEvents: 'none',
|
||||
zIndex: 2,
|
||||
};
|
||||
|
||||
return <div ref={containerRef} style={containerStyle} />;
|
||||
};
|
||||
|
||||
export default EmojiRain;
|
@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import EmojiRain from './component';
|
||||
import UserReaction from '/imports/api/user-reaction';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
|
||||
const EmojiRainContainer = (props) => <EmojiRain {...props} />;
|
||||
|
||||
export default withTracker(() => ({
|
||||
reactions: UserReaction.find({ meetingId: Auth.meetingID }).fetch(),
|
||||
}))(EmojiRainContainer);
|
@ -0,0 +1,9 @@
|
||||
const getInteractionsButtonCoordenates = () => {
|
||||
const el = document.getElementById('interactionsButton');
|
||||
const coordenada = el.getBoundingClientRect();
|
||||
return coordenada;
|
||||
};
|
||||
|
||||
export default {
|
||||
getInteractionsButtonCoordenates,
|
||||
};
|
@ -4,7 +4,6 @@ import { injectIntl, defineMessages } from 'react-intl';
|
||||
import TooltipContainer from '/imports/ui/components/common/tooltip/container';
|
||||
import { Session } from 'meteor/session';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import { Emoji } from 'emoji-mart';
|
||||
import UserAvatar from '/imports/ui/components/user-avatar/component';
|
||||
import Icon from '/imports/ui/components/common/icon/component';
|
||||
import lockContextContainer from '/imports/ui/components/lock-viewers/context/container';
|
||||
@ -363,6 +362,7 @@ class UserListItem extends PureComponent {
|
||||
label: intl.formatMessage(messages.backTriggerLabel),
|
||||
onClick: () => this.setState({ showNestedOptions: false }),
|
||||
icon: 'left_arrow',
|
||||
divider: true,
|
||||
},
|
||||
{
|
||||
allowed: showNestedOptions && isMeteorConnected && allowedToChangeStatus,
|
||||
@ -638,20 +638,30 @@ class UserListItem extends PureComponent {
|
||||
} = this.props;
|
||||
|
||||
const emojiProps = {
|
||||
native: true,
|
||||
size: '1.3rem',
|
||||
};
|
||||
|
||||
let userAvatarFiltered = user.avatar;
|
||||
|
||||
const emojiIcons = [
|
||||
{
|
||||
id: 'hand',
|
||||
native: '✋',
|
||||
},
|
||||
{
|
||||
id: 'clock7',
|
||||
native: '⏰',
|
||||
},
|
||||
];
|
||||
|
||||
const getIconUser = () => {
|
||||
if (user.raiseHand === true) {
|
||||
return isReactionsEnabled
|
||||
? <Emoji key="hand" emoji={{ id: 'hand' }} {...emojiProps} />
|
||||
? <em-emoji key={emojiIcons[0].id} native={emojiIcons[0].native} emoji={emojiIcons[0]} {...emojiProps} />
|
||||
: <Icon iconName={normalizeEmojiName('raiseHand')} />;
|
||||
} if (user.away === true) {
|
||||
return isReactionsEnabled
|
||||
? <Emoji key="away" emoji={{ id: 'clock7' }} {...emojiProps} />
|
||||
? <em-emoji key="away" native={emojiIcons[1].native} emoji={emojiIcons[1]} {...emojiProps} />
|
||||
: <Icon iconName={normalizeEmojiName('away')} />;
|
||||
} if (user.emoji !== 'none' && user.emoji !== 'notAway') {
|
||||
return <Icon iconName={normalizeEmojiName(user.emoji)} />;
|
||||
|
20
bigbluebutton-html5/package-lock.json
generated
20
bigbluebutton-html5/package-lock.json
generated
@ -828,6 +828,16 @@
|
||||
"kuler": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@emoji-mart/data": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@emoji-mart/data/-/data-1.1.2.tgz",
|
||||
"integrity": "sha512-1HP8BxD2azjqWJvxIaWAMyTySeZY0Osr83ukYjltPVkNXeJvTz7yDrPLBtnrD5uqJ3tg4CcLuuBW09wahqL/fg=="
|
||||
},
|
||||
"@emoji-mart/react": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@emoji-mart/react/-/react-1.1.1.tgz",
|
||||
"integrity": "sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g=="
|
||||
},
|
||||
"@emotion/babel-plugin": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
|
||||
@ -4395,13 +4405,9 @@
|
||||
"integrity": "sha512-ZzPqGKghdVzlQJ+qpfE+r6EB321zed7e5JsvHIlMM4zPFF8okXUkF5Of7h7F3l3cltPL0rG7YVmlp5Qro7RQLA=="
|
||||
},
|
||||
"emoji-mart": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-3.0.1.tgz",
|
||||
"integrity": "sha512-sxpmMKxqLvcscu6mFn9ITHeZNkGzIvD0BSNFE/LJESPbCA8s1jM6bCDPjWbV31xHq7JXaxgpHxLB54RCbBZSlg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-5.5.2.tgz",
|
||||
"integrity": "sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A=="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
|
@ -32,6 +32,8 @@
|
||||
"@apollo/client": "^3.7.10",
|
||||
"@babel/runtime": "^7.17.9",
|
||||
"@browser-bunyan/server-stream": "^1.8.0",
|
||||
"@emoji-mart/data": "^1.1.2",
|
||||
"@emoji-mart/react": "^1.1.1",
|
||||
"@emotion/react": "^11.10.8",
|
||||
"@emotion/styled": "^11.10.8",
|
||||
"@jitsi/sdp-interop": "0.1.14",
|
||||
@ -50,7 +52,7 @@
|
||||
"browser-bunyan": "^1.8.0",
|
||||
"classnames": "^2.2.6",
|
||||
"darkreader": "^4.9.46",
|
||||
"emoji-mart": "^3.0.1",
|
||||
"emoji-mart": "^5.5.2",
|
||||
"eventemitter2": "~6.4.6",
|
||||
"fast-json-patch": "^3.1.1",
|
||||
"fastdom": "^1.0.10",
|
||||
|
@ -152,6 +152,14 @@ public:
|
||||
# Enables the new raiseHand icon inside of the reaction menu (introduced in BBB 2.7)
|
||||
# If both reactionsButton and raiseHandActionButton are enabled, reactionsButton takes precedence.
|
||||
enabled: true
|
||||
emojiRain:
|
||||
# If true, new reactions will be activated
|
||||
enabled: false
|
||||
# Can set the throttle, the number of emojis that will be displayed and their size
|
||||
intervalEmojis: 2000
|
||||
numberOfEmojis: 5
|
||||
# emojiSize: size of the emoji in 'em' units
|
||||
emojiSize: 2
|
||||
# If enabled, before joining microphone the client will perform a trickle
|
||||
# ICE against Kurento and use the information about successfull
|
||||
# candidate-pairs to filter out local candidates in SIP.js's SDP.
|
||||
@ -592,13 +600,25 @@ public:
|
||||
autoConvertEmoji: true
|
||||
emojiPicker:
|
||||
enable: false
|
||||
frequentEmojiSortOnClick: false
|
||||
# e.g.: disableEmojis: ['1F595','1F922']
|
||||
# e.g.: disableEmojis: ['grin','laughing']
|
||||
disableEmojis: []
|
||||
allowedElements: ['a', 'code', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'ol', 'ul', 'p', 'strong']
|
||||
userReaction:
|
||||
enabled: true
|
||||
expire: 60
|
||||
reactions:
|
||||
- id: 'smiley'
|
||||
native: '😃'
|
||||
- id: 'neutral_face'
|
||||
native: '😐'
|
||||
- id: 'slightly_frowning_face'
|
||||
native: '🙁'
|
||||
- id: '+1'
|
||||
native: '👍'
|
||||
- id: '-1'
|
||||
native: '👎'
|
||||
- id: 'clap'
|
||||
native: '👏'
|
||||
userStatus:
|
||||
enabled: false
|
||||
notes:
|
||||
|
Loading…
Reference in New Issue
Block a user