mirror of https://github.com/Troplo/Colubrina.git
495 lines
15 KiB
Vue
495 lines
15 KiB
Vue
<template>
|
|
<div>
|
|
<template>
|
|
<v-toolbar
|
|
v-if="message.reply"
|
|
:key="message.keyId + '-reply-toolbar'"
|
|
elevation="0"
|
|
height="40"
|
|
color="card"
|
|
style="cursor: pointer"
|
|
@click="jumpToMessage(message.replyId)"
|
|
>
|
|
<v-icon class="mr-2"> mdi-reply </v-icon>
|
|
<v-avatar size="24" class="mr-2">
|
|
<v-img
|
|
v-if="message.reply.user.avatar"
|
|
:src="
|
|
$store.state.baseURL + '/usercontent/' + message.reply.user.avatar
|
|
"
|
|
class="elevation-1"
|
|
/>
|
|
<v-icon v-else class="elevation-1"> mdi-account </v-icon>
|
|
</v-avatar>
|
|
<template v-if="message.reply.attachments.length">
|
|
<v-icon class="mr-2"> mdi-file-image </v-icon>
|
|
</template>
|
|
<template
|
|
v-if="!message.reply.content && message.reply.attachments.length"
|
|
>
|
|
Click to view attachment
|
|
</template>
|
|
{{ message.reply.content.substring(0, 100) }}
|
|
</v-toolbar>
|
|
<v-list-item
|
|
:id="'message-' + index"
|
|
:key="message.keyId"
|
|
:class="{
|
|
'pa-0': $vuetify.breakpoint.mobile,
|
|
'mentioned-message': mentioned
|
|
}"
|
|
class="message"
|
|
:dense="lastMessage"
|
|
:style="lastMessage ? 'margin-bottom: -5px; margin-top: -5px;' : ''"
|
|
@contextmenu="show($event, 'message', message)"
|
|
>
|
|
<v-avatar
|
|
v-if="!lastMessage"
|
|
size="45"
|
|
class="mr-2"
|
|
:class="{ 'hide-on-hover': message.type }"
|
|
>
|
|
<v-img
|
|
v-if="message.user.avatar && !message.type"
|
|
:src="$store.state.baseURL + '/usercontent/' + message.user.avatar"
|
|
class="elevation-1"
|
|
/>
|
|
<v-icon v-else-if="!message.type" class="elevation-1">
|
|
mdi-account
|
|
</v-icon>
|
|
<v-icon
|
|
v-else-if="message.type === 'leave'"
|
|
color="red"
|
|
class="mr-2 ml-1"
|
|
size="32"
|
|
>
|
|
mdi-arrow-left
|
|
</v-icon>
|
|
<v-icon
|
|
v-else-if="message.type === 'join'"
|
|
size="32"
|
|
color="success"
|
|
class="mr-2 ml-1"
|
|
>
|
|
mdi-arrow-right
|
|
</v-icon>
|
|
<v-icon
|
|
v-else-if="message.type === 'pin'"
|
|
size="32"
|
|
color="grey"
|
|
class="mr-2 ml-1"
|
|
>
|
|
mdi-pin-outline
|
|
</v-icon>
|
|
<v-icon v-else size="32" color="grey" class="mr-2 ml-1">
|
|
mdi-pencil
|
|
</v-icon>
|
|
</v-avatar>
|
|
<v-tooltip top style="z-index: 15">
|
|
<template #activator="{ on }">
|
|
<small
|
|
v-if="lastMessage || message.type"
|
|
style="font-size: 9px; position: absolute"
|
|
class="grey--text message-date"
|
|
v-on="on"
|
|
>
|
|
{{ $date(message.createdAt).format("hh:mm A") }}
|
|
</small>
|
|
</template>
|
|
<span>
|
|
{{
|
|
$date(message.createdAt).format("DD/MM/YYYY, hh:mm:ss A")
|
|
}}</span
|
|
>
|
|
</v-tooltip>
|
|
<v-list-item-content :class="{ 'offset-message': lastMessage }">
|
|
<v-list-item-subtitle v-if="!lastMessage && !message.type">
|
|
{{ getName(message.user) }}
|
|
<v-chip
|
|
v-if="message.user.bot"
|
|
color="calendarNormalActivity"
|
|
small
|
|
>
|
|
<v-icon small> mdi-robot </v-icon>
|
|
</v-chip>
|
|
<small>
|
|
{{ $date(message.createdAt).format("hh:mm A, DD/MM/YYYY") }}
|
|
</small>
|
|
<v-tooltip v-if="message.edited" top>
|
|
<template #activator="{ on, attrs }">
|
|
<span v-bind="attrs" v-on="on">
|
|
<v-icon
|
|
color="grey"
|
|
small
|
|
style="
|
|
margin-bottom: 2px;
|
|
margin-left: 4px;
|
|
position: absolute;
|
|
"
|
|
>
|
|
mdi-pencil
|
|
</v-icon>
|
|
</span>
|
|
</template>
|
|
<span>
|
|
{{ $date(message.editedAt).format("DD/MM/YYYY hh:mm:ss A") }}
|
|
</span>
|
|
</v-tooltip>
|
|
</v-list-item-subtitle>
|
|
<span v-if="edit.id !== message.id" style="overflow-wrap: anywhere">
|
|
<span v-markdown>
|
|
{{ message.content }}
|
|
</span>
|
|
<v-tooltip v-if="message.edited && lastMessage" top>
|
|
<template #activator="{ on }">
|
|
<v-icon color="grey" small style="" v-on="on">
|
|
mdi-pencil
|
|
</v-icon>
|
|
</template>
|
|
<span>
|
|
{{ $date(message.editedAt).format("DD/MM/YYYY hh:mm:ss A") }}
|
|
</span>
|
|
</v-tooltip>
|
|
</span>
|
|
|
|
<template v-if="edit.id !== message.id">
|
|
<Embed
|
|
v-for="(embed, index) in message.embeds"
|
|
:id="'embed-' + index"
|
|
:key="index"
|
|
:embed="embed"
|
|
:set-image-preview="setImagePreview"
|
|
/>
|
|
<v-row v-if="message.poll" no-gutters>
|
|
<Poll :message="message" />
|
|
</v-row>
|
|
</template>
|
|
<template v-if="edit.id !== message.id">
|
|
<v-card
|
|
v-for="(attachment, index) in message.attachments"
|
|
:id="'attachment-' + index"
|
|
:key="attachment.id"
|
|
:max-width="500"
|
|
:min-width="!$vuetify.breakpoint.mobile ? 400 : 0"
|
|
elevation="0"
|
|
color="card"
|
|
>
|
|
<v-hover
|
|
v-if="
|
|
attachment.extension === 'jpg' ||
|
|
attachment.extension === 'png' ||
|
|
attachment.extension === 'jpeg' ||
|
|
attachment.extension === 'gif'
|
|
"
|
|
v-slot="{ hover }"
|
|
>
|
|
<div>
|
|
<v-img
|
|
contain
|
|
:max-width="500"
|
|
:max-height="500"
|
|
:src="
|
|
$store.state.baseURL +
|
|
'/usercontent/' +
|
|
attachment.attachment
|
|
"
|
|
:min-height="250"
|
|
:min-width="250"
|
|
@click="setImagePreview(attachment)"
|
|
>
|
|
<template #placeholder>
|
|
<v-row
|
|
class="fill-height ma-0"
|
|
align="center"
|
|
justify="center"
|
|
>
|
|
<v-progress-circular
|
|
indeterminate
|
|
color="grey lighten-5"
|
|
/>
|
|
</v-row>
|
|
</template>
|
|
<template #default>
|
|
<v-fade-transition v-if="hover">
|
|
<v-overlay absolute>
|
|
<v-icon large> mdi-arrow-expand-all </v-icon>
|
|
</v-overlay>
|
|
</v-fade-transition>
|
|
</template>
|
|
</v-img>
|
|
</div>
|
|
</v-hover>
|
|
<v-card-text v-else>
|
|
<v-icon class="mr-2" :size="48">
|
|
{{ fileTypes[attachment.extension] || "mdi-file" }}
|
|
</v-icon>
|
|
<span>
|
|
{{ attachment.name }}
|
|
</span>
|
|
</v-card-text>
|
|
<v-card-actions
|
|
v-if="
|
|
attachment.extension !== 'jpg' &&
|
|
attachment.extension !== 'png' &&
|
|
attachment.extension !== 'jpeg' &&
|
|
attachment.extension !== 'gif'
|
|
"
|
|
>
|
|
{{ attachment.name }} -
|
|
{{ friendlySize(attachment.size) }}
|
|
<v-spacer />
|
|
<v-btn
|
|
text
|
|
icon
|
|
:href="
|
|
$store.state.baseURL +
|
|
'/usercontent/' +
|
|
attachment.attachment
|
|
"
|
|
target="_blank"
|
|
>
|
|
<v-icon> mdi-download </v-icon>
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</template>
|
|
<CommsInput
|
|
v-if="edit.id === message.id"
|
|
:edit="edit"
|
|
:chat="chat"
|
|
:auto-scroll="autoScroll"
|
|
:end-edit="endEdit"
|
|
/>
|
|
</v-list-item-content>
|
|
<v-card
|
|
v-if="!$vuetify.breakpoint.mobile"
|
|
elevation="8"
|
|
color="card"
|
|
class="message-action-card"
|
|
>
|
|
<v-tooltip top>
|
|
<template #activator="{ on }">
|
|
<span v-on="on">
|
|
<v-btn
|
|
v-if="
|
|
message.userId === $store.state.user.id ||
|
|
chat.rank === 'admin'
|
|
"
|
|
icon
|
|
v-on="on"
|
|
@click="deleteMessage(message)"
|
|
>
|
|
<v-icon> mdi-delete </v-icon>
|
|
</v-btn>
|
|
</span>
|
|
</template>
|
|
<span> Delete </span>
|
|
</v-tooltip>
|
|
<v-tooltip top>
|
|
<template #activator="{ on }">
|
|
<span v-on="on">
|
|
<v-btn
|
|
v-if="
|
|
message.userId === $store.state.user.id &&
|
|
edit.id !== message.id
|
|
"
|
|
icon
|
|
v-on="on"
|
|
@click="
|
|
edit.content = message.content
|
|
edit.editing = true
|
|
edit.id = message.id
|
|
"
|
|
>
|
|
<v-icon> mdi-pencil </v-icon>
|
|
</v-btn>
|
|
</span>
|
|
</template>
|
|
<span> Edit </span>
|
|
</v-tooltip>
|
|
<v-tooltip top>
|
|
<template #activator="{ on }">
|
|
<span v-on="on">
|
|
<v-btn
|
|
v-if="
|
|
message.userId === $store.state.user.id &&
|
|
edit.id === message.id
|
|
"
|
|
icon
|
|
v-on="on"
|
|
@click="
|
|
edit.content = ''
|
|
edit.editing = false
|
|
edit.id = null
|
|
"
|
|
>
|
|
<v-icon> mdi-close </v-icon>
|
|
</v-btn>
|
|
</span>
|
|
</template>
|
|
<span> Discard Edits </span>
|
|
</v-tooltip>
|
|
<v-tooltip top>
|
|
<template #activator="{ on }">
|
|
<span v-on="on">
|
|
<v-btn
|
|
icon
|
|
@click="
|
|
replying(message)
|
|
focusInput()
|
|
"
|
|
v-on="on"
|
|
>
|
|
<v-icon> mdi-reply </v-icon>
|
|
</v-btn>
|
|
</span>
|
|
</template>
|
|
<span> Reply </span>
|
|
</v-tooltip>
|
|
<v-tooltip top>
|
|
<template #activator="{ on }">
|
|
<span v-on="on">
|
|
<v-btn
|
|
v-if="chat.rank === 'admin' || chat.chat.type === 'direct'"
|
|
icon
|
|
v-on="on"
|
|
@click="
|
|
pinMessage()
|
|
focusInput()
|
|
"
|
|
>
|
|
<v-icon> mdi-pin </v-icon>
|
|
</v-btn>
|
|
</span>
|
|
</template>
|
|
<span> Pin to Chat </span>
|
|
</v-tooltip>
|
|
<v-menu v-if="$store.state.site.release === 'dev'" offset-y>
|
|
<template #activator="{ on, attrs }">
|
|
<v-btn icon v-bind="attrs" v-on="on">
|
|
<v-icon> mdi-dots-horizontal </v-icon>
|
|
</v-btn>
|
|
</template>
|
|
<v-list>
|
|
<v-list-item><v-icon>mdi-delete</v-icon> Delete </v-list-item>
|
|
</v-list>
|
|
</v-menu>
|
|
</v-card>
|
|
</v-list-item>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Embed from "./Embed.vue"
|
|
import CommsInput from "./CommsInput.vue"
|
|
import AjaxErrorHandler from "@/lib/errorHandler.js"
|
|
import Poll from "@/components/Poll"
|
|
|
|
export default {
|
|
name: "Message",
|
|
components: {
|
|
Poll,
|
|
CommsInput,
|
|
Embed
|
|
},
|
|
props: [
|
|
"message",
|
|
"edit",
|
|
"jumpToMessage",
|
|
"focusInput",
|
|
"replying",
|
|
"getName",
|
|
"chat",
|
|
"endEdit",
|
|
"autoScroll",
|
|
"index",
|
|
"show",
|
|
"setImagePreview",
|
|
"deleteMessage",
|
|
"lastMessage"
|
|
],
|
|
data() {
|
|
return {
|
|
graphOptions: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
title: {
|
|
display: false
|
|
}
|
|
},
|
|
fileTypes: {
|
|
png: "mdi-file-image",
|
|
jpg: "mdi-file-image",
|
|
jpeg: "mdi-file-image",
|
|
gif: "mdi-file-image",
|
|
mp4: "mdi-file-video",
|
|
mp3: "mdi-file-music",
|
|
pdf: "mdi-file-pdf",
|
|
doc: "mdi-file-word",
|
|
docx: "mdi-file-word",
|
|
xls: "mdi-file-excel",
|
|
xlsx: "mdi-file-excel",
|
|
ppt: "mdi-file-powerpoint",
|
|
pptx: "mdi-file-powerpoint",
|
|
zip: "mdi-file-zip",
|
|
rar: "mdi-file-zip",
|
|
txt: "mdi-file-document",
|
|
csv: "mdi-file-spreadsheet",
|
|
html: "mdi-file-html",
|
|
htm: "mdi-file-html",
|
|
js: "mdi-file-code",
|
|
json: "mdi-file-code",
|
|
css: "mdi-file-css",
|
|
otf: "mdi-file-font",
|
|
ttf: "mdi-file-font",
|
|
woff: "mdi-file-font",
|
|
woff2: "mdi-file-font",
|
|
otf2: "mdi-file-font",
|
|
ttf2: "mdi-file-font",
|
|
eot: "mdi-file-font",
|
|
svg: "mdi-file-image",
|
|
ico: "mdi-file-image",
|
|
webp: "mdi-file-image",
|
|
other: "mdi-file",
|
|
xml: "mdi-file-code"
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
mentioned() {
|
|
return this.message.content
|
|
.toLowerCase()
|
|
.includes(this.$store.state.user.username.toLowerCase())
|
|
}
|
|
},
|
|
methods: {
|
|
pinMessage() {
|
|
this.axios
|
|
.post(`/api/v1/communications/${this.chat.id}/pins`, {
|
|
messageId: this.message.id
|
|
})
|
|
.then((res) => {
|
|
this.$toast.success(res.data.message)
|
|
})
|
|
.catch((e) => {
|
|
AjaxErrorHandler(this.$store)(e)
|
|
})
|
|
},
|
|
friendlySize(size) {
|
|
if (size < 1024) {
|
|
return size + " bytes"
|
|
} else if (size < 1048576) {
|
|
return (size / 1024).toFixed(2) + " KB"
|
|
} else if (size < 1073741824) {
|
|
return (size / 1048576).toFixed(2) + " MB"
|
|
} else {
|
|
return (size / 1073741824).toFixed(2) + " GB"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped></style>
|