9dbf647f7e
* Mentions: rename method to what it's doing * Mentions: make <esc> dismiss the window
230 lines
4.7 KiB
Vue
230 lines
4.7 KiB
Vue
<template>
|
||
<div
|
||
v-if="isOpen"
|
||
id="mentions-popup-container"
|
||
@click="containerClick"
|
||
@contextmenu="containerClick"
|
||
>
|
||
<div class="mentions-popup">
|
||
<div class="mentions-popup-title">
|
||
Recent mentions
|
||
<button
|
||
v-if="resolvedMessages.length"
|
||
class="btn dismiss-all-mentions"
|
||
@click="dismissAllMentions()"
|
||
>
|
||
Dismiss all
|
||
</button>
|
||
</div>
|
||
<template v-if="resolvedMessages.length === 0">
|
||
<p v-if="isLoading">Loading…</p>
|
||
<p v-else>You have no recent mentions.</p>
|
||
</template>
|
||
<template v-for="message in resolvedMessages" v-else>
|
||
<div :key="message.msgId" :class="['msg', message.type]">
|
||
<div class="mentions-info">
|
||
<div>
|
||
<span class="from">
|
||
<Username :user="message.from" />
|
||
<template v-if="message.channel">
|
||
in {{ message.channel.channel.name }} on
|
||
{{ message.channel.network.name }}
|
||
</template>
|
||
<template v-else> in unknown channel </template>
|
||
</span>
|
||
<span :title="message.localetime" class="time">
|
||
{{ messageTime(message.time) }}
|
||
</span>
|
||
</div>
|
||
<div>
|
||
<span
|
||
class="close-tooltip tooltipped tooltipped-w"
|
||
aria-label="Dismiss this mention"
|
||
>
|
||
<button
|
||
class="msg-dismiss"
|
||
aria-label="Dismiss this mention"
|
||
@click="dismissMention(message)"
|
||
></button>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="content" dir="auto">
|
||
<ParsedMessage :network="null" :message="message" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style>
|
||
#mentions-popup-container {
|
||
z-index: 8;
|
||
}
|
||
|
||
.mentions-popup {
|
||
background-color: var(--window-bg-color);
|
||
position: absolute;
|
||
width: 400px;
|
||
right: 80px;
|
||
top: 55px;
|
||
max-height: 400px;
|
||
overflow-y: auto;
|
||
z-index: 2;
|
||
padding: 10px;
|
||
}
|
||
|
||
.mentions-popup > .mentions-popup-title {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 10px;
|
||
font-size: 20px;
|
||
}
|
||
|
||
.mentions-popup .mentions-info {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.mentions-popup .msg {
|
||
margin-bottom: 15px;
|
||
user-select: text;
|
||
}
|
||
|
||
.mentions-popup .msg:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.mentions-popup .msg .content {
|
||
background-color: var(--highlight-bg-color);
|
||
border-radius: 5px;
|
||
padding: 6px;
|
||
margin-top: 2px;
|
||
word-wrap: break-word;
|
||
word-break: break-word; /* Webkit-specific */
|
||
}
|
||
|
||
.mentions-popup .msg-dismiss::before {
|
||
font-size: 20px;
|
||
font-weight: normal;
|
||
display: inline-block;
|
||
line-height: 16px;
|
||
text-align: center;
|
||
content: "×";
|
||
}
|
||
|
||
.mentions-popup .msg-dismiss:hover {
|
||
color: var(--link-color);
|
||
}
|
||
|
||
.mentions-popup .dismiss-all-mentions {
|
||
margin: 0;
|
||
padding: 4px 6px;
|
||
}
|
||
|
||
@media (min-height: 500px) {
|
||
.mentions-popup {
|
||
max-height: 60vh;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.mentions-popup {
|
||
border-radius: 0;
|
||
border: 0;
|
||
box-shadow: none;
|
||
width: 100%;
|
||
max-height: none;
|
||
right: 0;
|
||
left: 0;
|
||
bottom: 0;
|
||
top: 45px; /* header height */
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
import Username from "./Username.vue";
|
||
import ParsedMessage from "./ParsedMessage.vue";
|
||
import socket from "../js/socket";
|
||
import eventbus from "../js/eventbus";
|
||
import localetime from "../js/helpers/localetime";
|
||
import dayjs from "dayjs";
|
||
import relativeTime from "dayjs/plugin/relativeTime";
|
||
|
||
dayjs.extend(relativeTime);
|
||
|
||
export default {
|
||
name: "Mentions",
|
||
components: {
|
||
Username,
|
||
ParsedMessage,
|
||
},
|
||
data() {
|
||
return {
|
||
isOpen: false,
|
||
isLoading: false,
|
||
};
|
||
},
|
||
computed: {
|
||
resolvedMessages() {
|
||
const messages = this.$store.state.mentions.slice().reverse();
|
||
|
||
for (const message of messages) {
|
||
message.localetime = localetime(message.time);
|
||
message.channel = this.$store.getters.findChannel(message.chanId);
|
||
}
|
||
|
||
return messages;
|
||
},
|
||
},
|
||
watch: {
|
||
"$store.state.mentions"() {
|
||
this.isLoading = false;
|
||
},
|
||
},
|
||
mounted() {
|
||
eventbus.on("mentions:toggle", this.togglePopup);
|
||
eventbus.on("escapekey", this.closePopup);
|
||
},
|
||
destroyed() {
|
||
eventbus.off("mentions:toggle", this.togglePopup);
|
||
eventbus.off("escapekey", this.closePopup);
|
||
},
|
||
methods: {
|
||
messageTime(time) {
|
||
return dayjs(time).fromNow();
|
||
},
|
||
dismissMention(message) {
|
||
this.$store.state.mentions.splice(
|
||
this.$store.state.mentions.findIndex((m) => m.msgId === message.msgId),
|
||
1
|
||
);
|
||
|
||
socket.emit("mentions:dismiss", message.msgId);
|
||
},
|
||
dismissAllMentions() {
|
||
this.$store.state.mentions = [];
|
||
socket.emit("mentions:dismiss_all");
|
||
},
|
||
containerClick(event) {
|
||
if (event.currentTarget === event.target) {
|
||
this.isOpen = false;
|
||
}
|
||
},
|
||
togglePopup() {
|
||
this.isOpen = !this.isOpen;
|
||
|
||
if (this.isOpen) {
|
||
this.isLoading = true;
|
||
socket.emit("mentions:get");
|
||
}
|
||
},
|
||
closePopup() {
|
||
this.isOpen = false;
|
||
},
|
||
},
|
||
};
|
||
</script>
|