Video Button in MessageBox + Various Improvements
MessageBox Improvements (Card Style): * Rearrange the buttons by the username (Send DM, Mute, Takeback) by putting the lesser used options into a drop-down overflow menu to make room for adding a Video button, to easily see someone's webcam when they are broadcasting or to see if you are already watching it. * The visible buttons now are: Send DMs, Open Video, and Overflow. * The Overflow menu contains: Mute, Takeback, Hide Message * If the user is not on video, only DMs and Overflow buttons are shown. * Spell out the word "Translate" on the Google Translate button, as a lot of users were not aware of what that button did. MessageBox Improvements (Compact style): * The Video button is added in between the current Overflow Menu and Emojis Other Improvements: * On the MessageBox, when a user is offline, their display name will be crossed out and their avatar image is turned to grayscale. * On your DMs List: offline users will also have grayscale avatars.
This commit is contained in:
parent
2268209998
commit
927d798bc7
41
src/App.vue
41
src/App.vue
|
@ -5004,7 +5004,8 @@ export default {
|
|||
<div class="column is-narrow pr-0" style="position: relative">
|
||||
<img v-if="avatarForUsername(normalizeUsername(c.channel))"
|
||||
:src="avatarForUsername(normalizeUsername(c.channel))" width="24"
|
||||
height="24" alt="">
|
||||
height="24" alt=""
|
||||
:class="{ 'offline-avatar': isUserOffline(c.name) }">
|
||||
<img v-else src="/static/img/shy.png" width="24" height="24">
|
||||
</div>
|
||||
|
||||
|
@ -5247,13 +5248,32 @@ export default {
|
|||
|
||||
<div v-for="(msg, i) in chatHistory" v-bind:key="i">
|
||||
|
||||
<MessageBox :message="msg" :action="msg.action" :appearance="messageStyle"
|
||||
:position="i" :user="getUser(msg.username)" :is-offline="isUserOffline(msg.username)"
|
||||
:username="username" :website-url="config.website" :is-dnd="isUsernameDND(msg.username)"
|
||||
:is-muted="isMutedUser(msg.username)" :reactions="getReactions(msg)"
|
||||
:report-enabled="isWebhookEnabled('report')" :is-dm="isDM" :is-op="isOp"
|
||||
@open-profile="showProfileModal" @send-dm="openDMs" @mute-user="muteUser"
|
||||
@takeback="takeback" @remove="removeMessage" @report="reportMessage" @react="sendReact">
|
||||
<MessageBox
|
||||
:message="msg"
|
||||
:action="msg.action"
|
||||
:appearance="messageStyle"
|
||||
:position="i"
|
||||
:total-count="chatHistory.length"
|
||||
:user="getUser(msg.username)"
|
||||
:is-offline="isUserOffline(msg.username)"
|
||||
:username="username"
|
||||
:website-url="config.website"
|
||||
:is-dnd="isUsernameDND(msg.username)"
|
||||
:is-muted="isMutedUser(msg.username)"
|
||||
:reactions="getReactions(msg)"
|
||||
:report-enabled="isWebhookEnabled('report')"
|
||||
:is-dm="isDM"
|
||||
:is-op="isOp"
|
||||
:is-video-not-allowed="isVideoNotAllowed(getUser(msg.username))"
|
||||
:video-icon-class="webcamIconClass(getUser(msg.username))"
|
||||
@open-profile="showProfileModal"
|
||||
@open-video="openVideo"
|
||||
@send-dm="openDMs"
|
||||
@mute-user="muteUser"
|
||||
@takeback="takeback"
|
||||
@remove="removeMessage"
|
||||
@report="reportMessage"
|
||||
@react="sendReact">
|
||||
</MessageBox>
|
||||
|
||||
</div>
|
||||
|
@ -5548,4 +5568,9 @@ export default {
|
|||
.forcibly-single-line {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Grey avatar for offline user on your DMs */
|
||||
.offline-avatar {
|
||||
filter: grayscale();
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import EmojiPicker from 'vue3-emoji-picker';
|
||||
import LocalStorage from '../lib/LocalStorage';
|
||||
import ScamDetection from './ScamDetection.vue';
|
||||
import VideoFlag from '../lib/VideoFlag';
|
||||
import 'vue3-emoji-picker/css';
|
||||
|
||||
export default {
|
||||
|
@ -18,9 +19,14 @@ export default {
|
|||
reactions: Object, // emoji reactions on the message
|
||||
reportEnabled: Boolean, // Report Message webhook is available
|
||||
position: Number, // position of the message (0 to n), for the emoji menu to know which side to pop
|
||||
totalCount: Number, // total count of messages
|
||||
isDm: Boolean, // is in a DM thread (hide DM buttons)
|
||||
isOp: Boolean, // current user is Operator (always show takeback button)
|
||||
noButtons: Boolean, // hide all message buttons (e.g. for Report Modal)
|
||||
|
||||
// User webcam settings
|
||||
isVideoNotAllowed: Boolean,
|
||||
videoIconClass: String,
|
||||
},
|
||||
components: {
|
||||
EmojiPicker,
|
||||
|
@ -28,10 +34,12 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
VideoFlag: VideoFlag,
|
||||
|
||||
// Emoji picker visible
|
||||
showEmojiPicker: false,
|
||||
|
||||
// Message menu (compact displays)
|
||||
// Message menu (compact displays, and overflow button on card layout)
|
||||
menuVisible: false,
|
||||
|
||||
// Favorite emojis
|
||||
|
@ -96,6 +104,60 @@ export default {
|
|||
}
|
||||
return 'auto';
|
||||
},
|
||||
|
||||
// Unique ID component for dropdown menus.
|
||||
uniqueID() {
|
||||
// Messages sent by users always have a msgID, use that.
|
||||
if (this.message.msgID) {
|
||||
return this.message.msgID;
|
||||
}
|
||||
|
||||
// Others (e.g. ChatServer messages), return something unique.
|
||||
return `${this.position}-${this.user.username}-${this.message.at}-${Math.random()*99999}`;
|
||||
},
|
||||
|
||||
// TODO: make DRY, copied from WhoListRow.
|
||||
videoButtonClass() {
|
||||
let result = "";
|
||||
|
||||
// VIP background if their cam is set to VIPs only
|
||||
if ((this.user.video & VideoFlag.Active) && (this.user.video & VideoFlag.VipOnly)) {
|
||||
result = "has-background-vip ";
|
||||
}
|
||||
|
||||
// Colors and/or cursors.
|
||||
if ((this.user.video & VideoFlag.Active) && (this.user.video & VideoFlag.NSFW)) {
|
||||
result += "is-danger is-outlined";
|
||||
} else if ((this.user.video & VideoFlag.Active) && !(this.user.video & VideoFlag.NSFW)) {
|
||||
result += "is-link is-outlined";
|
||||
} else if (this.isVideoNotAllowed) {
|
||||
result += "cursor-notallowed";
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
videoButtonTitle() {
|
||||
// Mouse-over title text for the video button.
|
||||
let parts = ["Open video stream"];
|
||||
|
||||
if (this.user.video & VideoFlag.MutualRequired) {
|
||||
parts.push("mutual video sharing required");
|
||||
}
|
||||
|
||||
if (this.user.video & VideoFlag.MutualOpen) {
|
||||
parts.push("will auto-open your video");
|
||||
}
|
||||
|
||||
if (this.user.video & VideoFlag.VipOnly) {
|
||||
parts.push(`${this.vipConfig.Name} only`);
|
||||
}
|
||||
|
||||
if (this.user.video & VideoFlag.NonExplicit) {
|
||||
parts.push("prefers non-explicit video");
|
||||
}
|
||||
|
||||
return parts.join("; ");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openProfile() {
|
||||
|
@ -108,6 +170,10 @@ export default {
|
|||
});
|
||||
},
|
||||
|
||||
openVideo() {
|
||||
this.$emit('open-video', this.user);
|
||||
},
|
||||
|
||||
muteUser() {
|
||||
this.$emit('mute-user', this.message.username);
|
||||
},
|
||||
|
@ -213,10 +279,10 @@ export default {
|
|||
{{ prettyDate(message.at) }}
|
||||
</span>
|
||||
|
||||
<span @click="openProfile()" class="cursor-pointer">
|
||||
<span @click="openProfile()" class="cursor-pointer"
|
||||
:class="{ 'strikethru': isOffline }">
|
||||
<strong>{{ nickname }}</strong>
|
||||
<span v-if="isOffline" class="ml-1">(offline)</span>
|
||||
<small v-else class="ml-1">(@{{ message.username }})</small>
|
||||
<small class="ml-1">(@{{ message.username }})</small>
|
||||
</span>
|
||||
{{ message.message }}
|
||||
</div>
|
||||
|
@ -231,40 +297,36 @@ export default {
|
|||
|
||||
<!-- Card Style (default) -->
|
||||
<div v-else-if="appearance === 'cards' || !appearance" class="box mb-2 px-4 pt-3 pb-1 position-relative">
|
||||
<div class="media mb-0">
|
||||
<div class="media-left">
|
||||
|
||||
<!-- Profile picture, name and buttons row -->
|
||||
<div class="columns is-mobile mb-0">
|
||||
<div class="column is-narrow pr-0">
|
||||
<a :href="profileURL" @click.prevent="openProfile()">
|
||||
<figure class="image is-48x48">
|
||||
<img v-if="message.isChatServer" src="/static/img/server.png">
|
||||
<img v-else-if="message.isChatClient" src="/static/img/client.png">
|
||||
<img v-else-if="avatarURL" :src="avatarURL">
|
||||
<img v-else src="/static/img/shy.png">
|
||||
<img v-else-if="avatarURL" :src="avatarURL" :class="{'offline-avatar': isOffline}">
|
||||
<img v-else src="/static/img/shy.png" :class="{'offline-avatar': isOffline}">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<div class="columns is-mobile pb-0">
|
||||
<div class="column is-narrow pb-0">
|
||||
<strong :class="{
|
||||
'has-text-success is-dark': message.isChatServer,
|
||||
'has-text-warning is-dark': message.isAdmin,
|
||||
'has-text-danger': message.isChatClient
|
||||
}">
|
||||
<div class="column is-narrow pb-0 px-4">
|
||||
<div class="user-nickname mb-4">
|
||||
<strong :class="{
|
||||
'has-text-success is-dark': message.isChatServer,
|
||||
'has-text-warning is-dark': message.isAdmin,
|
||||
'has-text-danger': message.isChatClient
|
||||
}">
|
||||
|
||||
<!-- User nickname/display name -->
|
||||
{{ nickname }}
|
||||
<!-- User nickname/display name -->
|
||||
<span :class="{ 'strikethru': isOffline }">{{ nickname }}</span>
|
||||
|
||||
<!-- Offline now? -->
|
||||
<span v-if="isOffline">(offline)</span>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="column has-text-right pb-0">
|
||||
<small class="has-text-grey is-size-7" :title="message.at">{{ prettyDate(message.at) }}</small>
|
||||
</div>
|
||||
<span v-if="isOffline" class="ml-2">(offline)</span>
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<!-- User @username below it which may link to a profile URL if JWT -->
|
||||
<div class="columns is-mobile pt-0" v-if="(message.isChatClient || message.isChatServer)">
|
||||
<div class="columns is-mobile" v-if="(message.isChatClient || message.isChatServer)">
|
||||
<div class="column is-narrow pt-0">
|
||||
<small v-if="!(message.isChatClient || message.isChatServer)">
|
||||
<a v-if="profileURL" :href="profileURL" target="_blank" @click.prevent="openProfile()"
|
||||
|
@ -276,8 +338,8 @@ export default {
|
|||
<small v-else class="has-text-grey">internal</small>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="columns is-mobile pt-0">
|
||||
<div class="column is-narrow pt-0">
|
||||
<div v-else class="columns is-mobile py-0">
|
||||
<div class="column is-narrow py-0">
|
||||
<small v-if="!(message.isChatClient || message.isChatServer)">
|
||||
<a :href="profileURL || '#'" target="_blank" @click.prevent="openProfile()"
|
||||
class="has-text-grey">
|
||||
|
@ -287,7 +349,7 @@ export default {
|
|||
<small v-else class="has-text-grey">internal</small>
|
||||
</div>
|
||||
|
||||
<div class="column is-narrow pl-1 pt-0" v-if="!noButtons">
|
||||
<div class="column is-narrow px-1 py-0" v-if="!noButtons">
|
||||
<!-- DMs button -->
|
||||
<button type="button" v-if="!(message.username === username || isDm)"
|
||||
class="button is-small px-2" @click="openDMs()"
|
||||
|
@ -296,47 +358,76 @@ export default {
|
|||
<i class="fa fa-comment"></i>
|
||||
</button>
|
||||
|
||||
<!-- Mute button -->
|
||||
<button type="button" v-if="!(message.username === username)"
|
||||
class="button is-small px-2 ml-1" @click="muteUser()" title="Mute user">
|
||||
<i class="fa fa-comment-slash" :class="{
|
||||
'has-text-success': isMuted,
|
||||
'has-text-danger': !isMuted
|
||||
}"></i>
|
||||
</button>
|
||||
|
||||
<!-- Owner or admin: take back the message -->
|
||||
<button type="button" v-if="message.username === username || isOp"
|
||||
class="button is-small px-2 ml-1"
|
||||
title="Take back this message (delete it for everybody)" @click="takeback()"
|
||||
:data-msgid="message.msgID">
|
||||
<i class="fa fa-rotate-left has-text-danger"></i>
|
||||
</button>
|
||||
|
||||
<!-- Everyone else: can hide it locally -->
|
||||
<button type="button" v-if="message.username !== username"
|
||||
class="button is-small px-2 ml-1"
|
||||
title="Hide this message (delete it only for your view)" @click="removeMessage()">
|
||||
<i class="fa fa-trash"></i>
|
||||
<!-- Webcam button -->
|
||||
<button type="button" v-if="(user.video & VideoFlag.Active)"
|
||||
class="button is-small ml-1 px-2" :class="videoButtonClass"
|
||||
:title="videoButtonTitle"
|
||||
@click.prevent="openVideo()">
|
||||
<i class="fa" :class="videoIconClass"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Overflow menu for lesser used options -->
|
||||
<div class="column is-narrow pl-0 py-0 dropdown"
|
||||
:class="{ 'is-up': position === totalCount-1, 'is-active': menuVisible }"
|
||||
@click="menuVisible = !menuVisible">
|
||||
<div class="dropdown-trigger">
|
||||
<button type="button" class="button is-small" aria-haspopup="true"
|
||||
:aria-controls="`msg-overflow-menu-${uniqueID}`">
|
||||
<i class="fa fa-ellipsis-vertical"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu" :id="`msg-overflow-menu-${uniqueID}`">
|
||||
<div class="dropdown-content" role="menu">
|
||||
|
||||
<!-- Mute/Unmute User -->
|
||||
<a href="#" class="dropdown-item" v-if="!(message.username === username)"
|
||||
@click.prevent="muteUser()">
|
||||
<i class="fa fa-comment-slash mr-1" :class="{
|
||||
'has-text-success': isMuted,
|
||||
'has-text-danger': !isMuted
|
||||
}"></i>
|
||||
<span v-if="isMuted">Unmute user</span>
|
||||
<span v-else>Mute user</span>
|
||||
</a>
|
||||
|
||||
<!-- Owner/admin: take back message -->
|
||||
<a href="#" class="dropdown-item" v-if="message.msgID && (message.username === username || isOp)"
|
||||
@click.prevent="takeback()" :data-msgid="message.msgID">
|
||||
<i class="fa fa-rotate-left has-text-danger mr-1"></i>
|
||||
Take back
|
||||
</a>
|
||||
|
||||
<!-- Everyone else: hide message instead -->
|
||||
<a href="#" class="dropdown-item" v-if="message.username !== username"
|
||||
@click.prevent="removeMessage()">
|
||||
<i class="fa fa-trash mr-1"></i>
|
||||
Hide message
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column has-text-right pb-0 pl-0">
|
||||
<small class="has-text-grey is-size-7" :title="message.at">{{ prettyDate(message.at) }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Report & Emoji buttons -->
|
||||
<div v-if="message.msgID && !noButtons" class="emoji-button columns is-mobile is-gapless mb-0">
|
||||
<div v-if="!noButtons" class="emoji-button columns is-mobile is-gapless mb-0">
|
||||
<!-- Translate message button -->
|
||||
<div class="column">
|
||||
<button class="button is-small mr-1 py-2 has-text-success"
|
||||
<button class="button is-small mr-1 has-text-success"
|
||||
title="Translate this message using Google Translate"
|
||||
@click.prevent="translate()">
|
||||
<i class="fab fa-google has-text-success"></i>
|
||||
<span class="has-text-success ml-2">Translate</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Report message button -->
|
||||
<div class="column" v-if="reportEnabled && message.username !== username">
|
||||
<div class="column" v-if="message.msgID && reportEnabled && message.username !== username">
|
||||
<button class="button is-small is-outlined mr-1 py-2" :class="{
|
||||
'is-danger': !message.reported,
|
||||
'has-text-grey': message.reported
|
||||
|
@ -346,19 +437,19 @@ export default {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div class="column dropdown is-right"
|
||||
<div class="column dropdown is-right" v-if="message.msgID"
|
||||
:class="{ 'is-up': position >= 2, 'is-active': showEmojiPicker }"
|
||||
@click="showEmojiPicker = true">
|
||||
<div class="dropdown-trigger">
|
||||
<button type="button" class="button is-small px-2" aria-haspopup="true"
|
||||
:aria-controls="`react-menu-${message.msgID}`" @click.prevent="hideEmojiPicker()">
|
||||
:aria-controls="`react-menu-${uniqueID}`" @click.prevent="hideEmojiPicker()">
|
||||
<span>
|
||||
<i class="fa fa-heart has-text-grey"></i>
|
||||
<i class="fa fa-plus has-text-grey pl-1"></i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu" :id="`react-menu-${message.msgID}`" role="menu">
|
||||
<div class="dropdown-menu" :id="`react-menu-${uniqueID}`" role="menu">
|
||||
<div class="dropdown-content p-0">
|
||||
<!-- Emoji reactions menu -->
|
||||
<EmojiPicker v-if="showEmojiPicker" :native="true" :display-recent="true" :disable-skin-tones="true"
|
||||
|
@ -415,8 +506,8 @@ export default {
|
|||
<!-- Avatar icon -->
|
||||
<div class="column is-narrow px-1">
|
||||
<a :href="profileURL" @click.prevent="openProfile()" class="p-0">
|
||||
<img v-if="avatarURL" :src="avatarURL" width="16" height="16" alt="">
|
||||
<img v-else src="/static/img/shy.png" width="16" height="16">
|
||||
<img v-if="avatarURL" :src="avatarURL" width="16" height="16" alt="" :class="{'offline-avatar': isOffline}">
|
||||
<img v-else src="/static/img/shy.png" width="16" height="16" :class="{'offline-avatar': isOffline}">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
@ -437,11 +528,11 @@ export default {
|
|||
'has-text-warning is-dark': message.isAdmin,
|
||||
'has-text-danger': message.isChatClient
|
||||
}">
|
||||
{{ nickname }}
|
||||
<span :class="{ 'strikethru': isOffline }">{{ nickname }}</span>
|
||||
</span>
|
||||
|
||||
<small class="has-text-grey"
|
||||
:class="{ 'ml-1': appearance === 'compact' && nickname !== message.username }"
|
||||
:class="{ 'ml-1': appearance === 'compact' && nickname !== message.username, 'strikethru': isOffline }"
|
||||
v-if="!(message.isChatServer || message.isChatClient || message.isAdmin)">@{{ message.username
|
||||
}}</small>
|
||||
</a>]
|
||||
|
@ -481,7 +572,7 @@ export default {
|
|||
</div>
|
||||
|
||||
<!-- Emoji/Menu button -->
|
||||
<div v-if="message.msgID && !noButtons" class="column is-narrow pl-1">
|
||||
<div v-if="!noButtons" class="column is-narrow pl-1">
|
||||
|
||||
<div class="columns is-mobile is-gapless mb-0">
|
||||
<!-- More buttons menu (DM, mute, report, etc.) -->
|
||||
|
@ -490,20 +581,20 @@ export default {
|
|||
@click="menuVisible = !menuVisible">
|
||||
<div class="dropdown-trigger">
|
||||
<button type="button" class="button is-small px-2 mr-1" aria-haspopup="true"
|
||||
:aria-controls="`msg-menu-${message.msgID}`">
|
||||
:aria-controls="`msg-menu-${uniqueID}`">
|
||||
<small>
|
||||
<i class="fa fa-ellipsis-vertical"></i>
|
||||
</small>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu" :id="`msg-menu-${message.msgID}`" role="menu">
|
||||
<div class="dropdown-menu" :id="`msg-menu-${uniqueID}`" role="menu">
|
||||
<div class="dropdown-content">
|
||||
<a href="#" class="dropdown-item" v-if="message.username !== username"
|
||||
<a href="#" class="dropdown-item" v-if="message.msgID && message.username !== username"
|
||||
@click.prevent="openDMs()">
|
||||
<i class="fa fa-comment mr-1"></i> Direct Message
|
||||
</a>
|
||||
|
||||
<a href="#" class="dropdown-item" v-if="!(message.username === username)"
|
||||
<a href="#" class="dropdown-item" v-if="message.msgID && !message.username !== username"
|
||||
@click.prevent="muteUser()">
|
||||
<i class="fa fa-comment-slash mr-1" :class="{
|
||||
'has-text-success': isMuted,
|
||||
|
@ -513,7 +604,7 @@ export default {
|
|||
<span v-else>Mute user</span>
|
||||
</a>
|
||||
|
||||
<a href="#" class="dropdown-item" v-if="message.username === username || isOp"
|
||||
<a href="#" class="dropdown-item" v-if="message.msgID && message.username === username || isOp"
|
||||
@click.prevent="takeback()" :data-msgid="message.msgID">
|
||||
<i class="fa fa-rotate-left has-text-danger mr-1"></i>
|
||||
Take back
|
||||
|
@ -533,7 +624,7 @@ export default {
|
|||
</a>
|
||||
|
||||
<!-- Report button -->
|
||||
<a href="#" class="dropdown-item" v-if="reportEnabled && message.username !== username"
|
||||
<a href="#" class="dropdown-item" v-if="message.msgID && reportEnabled && message.username !== username"
|
||||
@click.prevent="reportMessage()">
|
||||
<i class="fa fa-flag mr-1" :class="{ 'has-text-danger': !message.reported }"></i>
|
||||
<span v-if="message.reported">Reported</span>
|
||||
|
@ -543,19 +634,31 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Webcam button -->
|
||||
<div class="column" v-if="(user.video & VideoFlag.Active)">
|
||||
<button type="button"
|
||||
class="button is-small mr-1 px-2" :class="videoButtonClass"
|
||||
:title="videoButtonTitle"
|
||||
@click.prevent="openVideo()">
|
||||
<small>
|
||||
<i class="fa" :class="videoIconClass"></i>
|
||||
</small>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Emoji reactions -->
|
||||
<div class="column dropdown is-right"
|
||||
<div class="column dropdown is-right" v-if="message.msgID"
|
||||
:class="{ 'is-up': position >= 2, 'is-active': showEmojiPicker }"
|
||||
@click="showEmojiPicker = true">
|
||||
<div class="dropdown-trigger">
|
||||
<button type="button" class="button is-small px-2" aria-haspopup="true"
|
||||
:aria-controls="`react-menu-${message.msgID}`" @click="hideEmojiPicker()">
|
||||
:aria-controls="`react-menu-${uniqueID}`" @click="hideEmojiPicker()">
|
||||
<small>
|
||||
<i class="fa fa-heart has-text-grey"></i>
|
||||
</small>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu" :id="`react-menu-${message.msgID}`" role="menu">
|
||||
<div class="dropdown-menu" :id="`react-menu-${uniqueID}`" role="menu">
|
||||
<div class="dropdown-content p-0">
|
||||
<!-- Emoji reactions menu -->
|
||||
<EmojiPicker v-if="showEmojiPicker" :native="true" :display-recent="true"
|
||||
|
@ -571,4 +674,25 @@ export default {
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
/* Trim display name lines on very small screens */
|
||||
.user-nickname {
|
||||
max-width: calc(150px + (100vw - 380px));
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.user-nickname {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Offline user styles */
|
||||
.offline-avatar {
|
||||
filter: grayscale();
|
||||
}
|
||||
.strikethru {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue
Block a user