2023-05-02 22:53:27 +02:00
|
|
|
<template>
|
|
|
|
<div
|
2023-06-09 12:40:47 +03:00
|
|
|
class="group rounded-lg m-2 shadow-lg hover:border-primary dark:hover:border-primary hover:border-solid hover:border-2 border-2 border-transparent even:bg-bg-light-discussion-odd dark:even:bg-bg-dark-discussion-odd flex flex-col flex-grow flex-wrap overflow-x-hidden p-4 pb-2">
|
|
|
|
<div class="flex flex-row gap-2 ">
|
|
|
|
<div class="flex-shrink-0 ">
|
2023-06-05 13:47:07 +03:00
|
|
|
<!-- AVATAR -->
|
2023-05-25 22:18:33 +03:00
|
|
|
<img :src="getImgUrl()" @error="defaultImg($event)" class="w-10 h-10 rounded-full object-fill text-red-700">
|
2023-05-02 22:53:27 +02:00
|
|
|
|
|
|
|
</div>
|
2023-05-07 23:00:30 +03:00
|
|
|
|
2023-06-09 12:40:47 +03:00
|
|
|
<div class="flex flex-col w-full flex-grow-0 ">
|
2023-06-05 13:47:07 +03:00
|
|
|
<div class="flex flex-row flex-grow items-start ">
|
|
|
|
<!-- SENDER NAME -->
|
2023-06-15 17:45:26 +03:00
|
|
|
<div class="flex flex-col mb-2">
|
|
|
|
<div class="drop-shadow-sm text-lg text-opacity-95 font-bold grow ">{{ message.sender }}
|
|
|
|
<!-- <button @click="toggleModel" class="expand-button">{{ expanded ? ' - ' : ' + ' }}</button>
|
2023-06-15 00:26:12 +02:00
|
|
|
<p v-if="expanded" class="drop-shadow-sm text-lg text-opacity-95 font-bold grow">
|
|
|
|
{{ message.model }}
|
2023-06-15 17:45:26 +03:00
|
|
|
</p> -->
|
|
|
|
|
2023-06-15 17:52:19 +03:00
|
|
|
</div>
|
2023-06-16 13:14:22 +03:00
|
|
|
<div class="text-sm text-gray-400 font-thin" v-if="message.created_at" :title="parsed_date">
|
2023-06-15 17:45:26 +03:00
|
|
|
{{ created_at }}
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
2023-06-08 13:35:25 +03:00
|
|
|
<div class="flex-grow ">
|
2023-06-05 13:47:07 +03:00
|
|
|
|
|
|
|
</div>
|
|
|
|
<!-- MESSAGE CONTROLS -->
|
2023-06-09 12:40:47 +03:00
|
|
|
<div class="flex-row justify-end mx-2">
|
2023-06-05 13:47:07 +03:00
|
|
|
<div class="invisible group-hover:visible flex flex-row ">
|
|
|
|
<!-- MESSAGE CONTROLS -->
|
|
|
|
<!-- EDIT CONFIRMATION -->
|
|
|
|
<div v-if="editMsgMode" class="flex items-center duration-75">
|
|
|
|
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2"
|
|
|
|
title="Cancel edit" type="button" @click.stop="editMsgMode = false">
|
|
|
|
<i data-feather="x"></i>
|
|
|
|
</button>
|
|
|
|
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 p-2"
|
|
|
|
title="Update message" type="button" @click.stop="updateMessage">
|
|
|
|
<i data-feather="check"></i>
|
|
|
|
</button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<div v-if="!editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2"
|
|
|
|
title="Edit message" @click.stop="editMsgMode = true">
|
|
|
|
<i data-feather="edit"></i>
|
|
|
|
</div>
|
|
|
|
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2"
|
|
|
|
title="Copy message to clipboard" @click.stop="copyContentToClipboard()">
|
|
|
|
<i data-feather="copy"></i>
|
|
|
|
</div>
|
|
|
|
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2" title="Resend message"
|
|
|
|
@click.stop="resendMessage()">
|
|
|
|
<i data-feather="refresh-cw"></i>
|
|
|
|
</div>
|
|
|
|
<!-- DELETE CONFIRMATION -->
|
|
|
|
<div v-if="deleteMsgMode" class="flex items-center duration-75">
|
|
|
|
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2"
|
|
|
|
title="Cancel removal" type="button" @click.stop="deleteMsgMode = false">
|
|
|
|
<i data-feather="x"></i>
|
|
|
|
</button>
|
|
|
|
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 p-2"
|
|
|
|
title="Confirm removal" type="button" @click.stop="deleteMsg()">
|
|
|
|
<i data-feather="check"></i>
|
|
|
|
</button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<div v-if="!deleteMsgMode" class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2"
|
|
|
|
title="Remove message" @click="deleteMsgMode = true">
|
|
|
|
<i data-feather="trash"></i>
|
|
|
|
</div>
|
|
|
|
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2" title="Upvote"
|
|
|
|
@click.stop="rankUp()">
|
|
|
|
<i data-feather="thumbs-up"></i>
|
|
|
|
</div>
|
|
|
|
<div class="flex flex-row items-center">
|
|
|
|
<div class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2" title="Downvote"
|
|
|
|
@click.stop="rankDown()">
|
|
|
|
<i data-feather="thumbs-down"></i>
|
|
|
|
</div>
|
|
|
|
<div v-if="message.rank != 0"
|
|
|
|
class="rounded-full px-2 text-sm flex items-center justify-center font-bold"
|
|
|
|
:class="message.rank > 0 ? 'bg-secondary' : 'bg-red-600'" title="Rank">{{
|
|
|
|
message.rank }}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2023-05-07 18:01:05 +03:00
|
|
|
</div>
|
2023-06-05 13:47:07 +03:00
|
|
|
|
2023-06-15 17:45:26 +03:00
|
|
|
<div class="overflow-x-auto w-full ">
|
2023-06-05 13:47:07 +03:00
|
|
|
<!-- MESSAGE CONTENT -->
|
2023-06-15 17:45:26 +03:00
|
|
|
<MarkdownRenderer ref="mdRender" v-if="!editMsgMode" :markdown-text="message.content">
|
2023-06-05 13:47:07 +03:00
|
|
|
</MarkdownRenderer>
|
|
|
|
<textarea v-if="editMsgMode" ref="mdTextarea" :rows="4"
|
|
|
|
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
|
|
:style="{ minHeight: mdRenderHeight + `px` }" placeholder="Enter message here..."
|
|
|
|
v-model="new_message_content"></textarea>
|
2023-05-02 22:53:27 +02:00
|
|
|
</div>
|
2023-06-15 17:45:26 +03:00
|
|
|
<!-- FOOTER -->
|
|
|
|
<div class="text-sm text-gray-400 mt-2">
|
|
|
|
<div class="flex flex-row items-center gap-2">
|
2023-06-15 17:52:19 +03:00
|
|
|
<p v-if="message.binding">Binding: <span class="font-thin">{{ message.binding }}</span></p>
|
|
|
|
<p v-if="message.model">Model: <span class="font-thin">{{ message.model }}</span></p>
|
|
|
|
<p v-if="message.seed">Seed: <span class="font-thin">{{ message.seed }}</span></p>
|
2023-06-15 17:45:26 +03:00
|
|
|
</div>
|
2023-06-05 13:47:07 +03:00
|
|
|
|
2023-06-15 17:45:26 +03:00
|
|
|
</div>
|
2023-05-02 22:53:27 +02:00
|
|
|
</div>
|
2023-06-05 13:47:07 +03:00
|
|
|
|
|
|
|
|
2023-05-07 18:01:05 +03:00
|
|
|
</div>
|
2023-06-05 13:47:07 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-05-02 22:53:27 +02:00
|
|
|
</div>
|
|
|
|
</template>
|
2023-06-15 00:26:12 +02:00
|
|
|
<style>
|
|
|
|
.expand-button {
|
2023-06-15 17:45:26 +03:00
|
|
|
margin-left: 10px;
|
|
|
|
/* Add space between sender and expand button */
|
|
|
|
margin-right: 10px;
|
|
|
|
/* Add space between sender and expand button */
|
|
|
|
background: none;
|
|
|
|
border: none;
|
|
|
|
padding: 0;
|
|
|
|
cursor: pointer;
|
2023-06-15 00:26:12 +02:00
|
|
|
}
|
|
|
|
</style>
|
2023-05-02 22:53:27 +02:00
|
|
|
<script>
|
2023-05-07 18:01:05 +03:00
|
|
|
import botImgPlaceholder from "../assets/logo.svg"
|
|
|
|
import userImgPlaceholder from "../assets/default_user.svg"
|
2023-05-25 22:18:33 +03:00
|
|
|
const bUrl = import.meta.env.VITE_GPT4ALL_API_BASEURL
|
2023-05-07 18:01:05 +03:00
|
|
|
import { nextTick } from 'vue'
|
2023-05-02 22:53:27 +02:00
|
|
|
import feather from 'feather-icons'
|
2023-05-07 10:20:59 +02:00
|
|
|
import MarkdownRenderer from './MarkdownRenderer.vue';
|
2023-05-02 22:53:27 +02:00
|
|
|
export default {
|
2023-05-17 09:25:21 -04:00
|
|
|
// eslint-disable-next-line vue/multi-word-component-names
|
2023-05-02 22:53:27 +02:00
|
|
|
name: 'Message',
|
2023-05-25 22:18:33 +03:00
|
|
|
emits: ['copy', 'delete', 'rankUp', 'rankDown', 'updateMessage', 'resendMessage'],
|
2023-05-07 10:20:59 +02:00
|
|
|
components: {
|
|
|
|
MarkdownRenderer
|
|
|
|
},
|
2023-05-02 22:53:27 +02:00
|
|
|
props: {
|
2023-05-25 22:18:33 +03:00
|
|
|
message: Object,
|
|
|
|
avatar: ''
|
2023-05-02 22:53:27 +02:00
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
2023-06-15 00:26:12 +02:00
|
|
|
expanded: false,
|
2023-05-25 22:18:33 +03:00
|
|
|
|
2023-05-07 23:00:30 +03:00
|
|
|
new_message_content: '',
|
|
|
|
showConfirmation: false,
|
|
|
|
editMsgMode: false,
|
|
|
|
deleteMsgMode: false,
|
2023-05-25 22:18:33 +03:00
|
|
|
mdRenderHeight: Number
|
2023-05-07 23:00:30 +03:00
|
|
|
|
2023-05-02 22:53:27 +02:00
|
|
|
}
|
2023-05-07 18:01:05 +03:00
|
|
|
}, mounted() {
|
2023-05-25 22:18:33 +03:00
|
|
|
|
2023-05-07 23:00:30 +03:00
|
|
|
this.new_message_content = this.message.content
|
2023-05-07 18:01:05 +03:00
|
|
|
nextTick(() => {
|
|
|
|
feather.replace()
|
2023-05-25 22:18:33 +03:00
|
|
|
|
|
|
|
this.mdRenderHeight = this.$refs.mdRender.$el.offsetHeight
|
|
|
|
|
|
|
|
|
2023-05-07 18:01:05 +03:00
|
|
|
})
|
2023-05-25 22:18:33 +03:00
|
|
|
|
2023-05-07 18:01:05 +03:00
|
|
|
}, methods: {
|
2023-06-15 00:26:12 +02:00
|
|
|
toggleModel() {
|
|
|
|
this.expanded = !this.expanded;
|
|
|
|
},
|
2023-05-07 18:01:05 +03:00
|
|
|
copyContentToClipboard() {
|
2023-05-07 15:40:57 +03:00
|
|
|
this.$emit('copy', this.message.content)
|
2023-06-05 13:47:07 +03:00
|
|
|
|
2023-05-07 18:01:05 +03:00
|
|
|
},
|
2023-05-07 23:00:30 +03:00
|
|
|
deleteMsg() {
|
|
|
|
this.$emit('delete', this.message.id)
|
|
|
|
this.deleteMsgMode = false
|
|
|
|
},
|
|
|
|
rankUp() {
|
|
|
|
this.$emit('rankUp', this.message.id)
|
|
|
|
|
|
|
|
},
|
|
|
|
rankDown() {
|
|
|
|
this.$emit('rankDown', this.message.id)
|
|
|
|
|
|
|
|
},
|
|
|
|
updateMessage() {
|
|
|
|
this.$emit('updateMessage', this.message.id, this.new_message_content)
|
|
|
|
this.editMsgMode = false
|
|
|
|
},
|
2023-05-25 22:18:33 +03:00
|
|
|
resendMessage() {
|
2023-05-08 17:04:44 +03:00
|
|
|
this.$emit('resendMessage', this.message.id, this.new_message_content)
|
|
|
|
},
|
2023-06-05 13:47:07 +03:00
|
|
|
getImgUrl() {
|
|
|
|
|
2023-05-07 18:01:05 +03:00
|
|
|
if (this.message.sender == "user") {
|
2023-05-25 22:18:33 +03:00
|
|
|
if (this.avatar) {
|
2023-06-05 13:47:07 +03:00
|
|
|
|
2023-05-25 22:18:33 +03:00
|
|
|
return this.avatar
|
|
|
|
}
|
2023-06-05 13:47:07 +03:00
|
|
|
|
2023-05-07 18:01:05 +03:00
|
|
|
return userImgPlaceholder;
|
|
|
|
|
|
|
|
}
|
2023-06-05 13:47:07 +03:00
|
|
|
if (this.avatar) {
|
|
|
|
return bUrl + this.avatar
|
|
|
|
}
|
|
|
|
return botImgPlaceholder;
|
2023-05-07 18:01:05 +03:00
|
|
|
|
2023-05-25 22:18:33 +03:00
|
|
|
},
|
|
|
|
defaultImg(event) {
|
|
|
|
event.target.src = botImgPlaceholder
|
|
|
|
},
|
2023-06-15 17:45:26 +03:00
|
|
|
parseDate(tdate) {
|
|
|
|
let system_date = new Date(Date.parse(tdate));
|
|
|
|
let user_date = new Date();
|
|
|
|
|
|
|
|
let diff = Math.floor((user_date - system_date) / 1000);
|
|
|
|
if (diff <= 1) {
|
|
|
|
return "just now";
|
|
|
|
}
|
|
|
|
if (diff < 20) {
|
|
|
|
return diff + " seconds ago";
|
|
|
|
}
|
|
|
|
if (diff < 40) {
|
|
|
|
return "half a minute ago";
|
|
|
|
}
|
|
|
|
if (diff < 60) {
|
|
|
|
return "less than a minute ago";
|
|
|
|
}
|
|
|
|
if (diff <= 90) {
|
|
|
|
return "one minute ago";
|
|
|
|
}
|
|
|
|
if (diff <= 3540) {
|
|
|
|
return Math.round(diff / 60) + " minutes ago";
|
|
|
|
}
|
|
|
|
if (diff <= 5400) {
|
|
|
|
return "1 hour ago";
|
|
|
|
}
|
|
|
|
if (diff <= 86400) {
|
|
|
|
return Math.round(diff / 3600) + " hours ago";
|
|
|
|
}
|
|
|
|
if (diff <= 129600) {
|
|
|
|
return "1 day ago";
|
|
|
|
}
|
|
|
|
if (diff < 604800) {
|
|
|
|
return Math.round(diff / 86400) + " days ago";
|
|
|
|
}
|
|
|
|
if (diff <= 777600) {
|
|
|
|
return "1 week ago";
|
|
|
|
}
|
|
|
|
return tdate;
|
2023-06-15 17:52:19 +03:00
|
|
|
},
|
|
|
|
prettyDate(time) {
|
|
|
|
let date = new Date((time || "").replace(/-/g, "/").replace(/[TZ]/g, " ")),
|
|
|
|
diff = (((new Date()).getTime() - date.getTime()) / 1000),
|
|
|
|
day_diff = Math.floor(diff / 86400);
|
|
|
|
|
|
|
|
if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31)
|
|
|
|
return;
|
|
|
|
|
|
|
|
return day_diff == 0 && (
|
|
|
|
diff < 60 && "just now" ||
|
|
|
|
diff < 120 && "1 minute ago" ||
|
|
|
|
diff < 3600 && Math.floor(diff / 60) + " minutes ago" ||
|
|
|
|
diff < 7200 && "1 hour ago" ||
|
|
|
|
diff < 86400 && Math.floor(diff / 3600) + " hours ago") ||
|
|
|
|
day_diff == 1 && "Yesterday" ||
|
|
|
|
day_diff < 7 && day_diff + " days ago" ||
|
|
|
|
day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago";
|
2023-06-15 17:45:26 +03:00
|
|
|
}
|
|
|
|
|
2023-05-07 18:01:05 +03:00
|
|
|
|
2023-05-07 23:00:30 +03:00
|
|
|
}, watch: {
|
|
|
|
showConfirmation() {
|
|
|
|
nextTick(() => {
|
|
|
|
feather.replace()
|
2023-05-25 22:18:33 +03:00
|
|
|
|
2023-05-07 23:00:30 +03:00
|
|
|
})
|
|
|
|
},
|
2023-05-10 22:27:18 +03:00
|
|
|
|
2023-05-25 22:18:33 +03:00
|
|
|
editMsgMode(val) {
|
|
|
|
|
|
|
|
if (!val) {
|
|
|
|
this.new_message_content = this.message.content
|
2023-05-07 23:00:30 +03:00
|
|
|
}
|
2023-05-10 22:27:18 +03:00
|
|
|
|
2023-05-07 23:00:30 +03:00
|
|
|
nextTick(() => {
|
|
|
|
feather.replace()
|
|
|
|
|
|
|
|
})
|
|
|
|
},
|
2023-05-25 22:18:33 +03:00
|
|
|
deleteMsgMode() {
|
2023-05-07 23:00:30 +03:00
|
|
|
nextTick(() => {
|
|
|
|
feather.replace()
|
|
|
|
|
|
|
|
})
|
|
|
|
},
|
2023-05-25 22:18:33 +03:00
|
|
|
|
|
|
|
},
|
|
|
|
computed: {
|
2023-06-15 17:45:26 +03:00
|
|
|
created_at() {
|
2023-06-15 17:52:19 +03:00
|
|
|
return this.prettyDate(this.message.created_at)
|
2023-05-25 22:18:33 +03:00
|
|
|
|
2023-06-16 13:14:22 +03:00
|
|
|
},
|
|
|
|
parsed_date() {
|
|
|
|
return new Date(Date.parse(this.message.created_at)).toLocaleString()
|
|
|
|
|
2023-06-15 17:45:26 +03:00
|
|
|
}
|
2023-05-07 23:00:30 +03:00
|
|
|
}
|
2023-05-07 18:01:05 +03:00
|
|
|
|
2023-05-10 22:27:18 +03:00
|
|
|
|
2023-05-02 22:53:27 +02:00
|
|
|
}
|
|
|
|
</script>
|