This commit is contained in:
Troplo 2022-09-22 17:40:00 +10:00
parent 88012b1930
commit 87976eac86
5 changed files with 243 additions and 114 deletions

View File

@ -1,6 +1,6 @@
{
"name": "colubrina",
"version": "1.0.29",
"version": "1.0.30",
"description": "Simple instant communication.",
"private": true,
"author": "Troplo <troplo@troplo.com>",

View File

@ -5,6 +5,7 @@
$vuetify.theme.themes[$vuetify.theme.dark ? 'dark' : 'light'].bg
"
>
<DevOverlay v-if="$store.state.site.release === 'dev'"></DevOverlay>
<v-overlay :value="$store.state.site.loading">
<v-progress-circular indeterminate size="64"></v-progress-circular>
</v-overlay>
@ -454,10 +455,12 @@
import AjaxErrorHandler from "@/lib/errorHandler"
import { VueFinalModal } from "vue-final-modal"
import Header from "@/components/Header"
import DevOverlay from "@/components/DevOverlay"
export default {
name: "App",
components: {
DevOverlay,
VueFinalModal,
Header,
editor: require("vue2-ace-editor")

View File

@ -1,3 +1,33 @@
.colubrina-alert {
position: fixed;
top: 0;
width: 100%;
z-index: 1000;
padding: 4px;
}
.dev-overlay {
position: absolute;
z-index: 2000;
background-color: rgba(0, 0, 0, 0.37);
text-align: center;
width: 300px;
}
.dev-header {
padding: 10px;
cursor: move;
z-index: 2001;
background-color: #2196F3;
}
.chat-col {
display: flex;
flex-direction: column-reverse;
overflow: auto;
height: 100%;
}
>>>.max-v-list-height {
max-height: 10px;
overflow-y: auto;

View File

@ -0,0 +1,91 @@
<template>
<div class="dev-overlay" id="dev-overlay">
<div class="dev-header" id="dev-header">Colubrina DevTools</div>
<v-container>
<v-btn @click="benchmark"
>Benchmark
<template v-if="isBenchmarking">({{ multiplier }}x)</template></v-btn
><br />
<template v-if="isBenchmarking"
>Please restart the Colubrina server to stop the benchmark.</template
><br />
<v-btn @click="deleteBenchmark">Delete benchuser messages</v-btn>
</v-container>
</div>
</template>
<script>
import AjaxErrorHandler from "@/lib/errorHandler"
export default {
name: "DevOverlay",
data() {
return {
isBenchmarking: false,
multiplier: 0
}
},
methods: {
deleteBenchmark() {
this.axios.delete("/api/v1/debug/bench").catch((e) => {
AjaxErrorHandler(this.$store)(e)
})
},
benchmark() {
this.axios
.get("/api/v1/debug/bench")
.then(() => {
this.isBenchmarking = true
this.multiplier += 1
})
.catch((e) => {
AjaxErrorHandler(this.$store)(e)
})
},
drag(element) {
let pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0
if (document.getElementById("dev-header")) {
// if present, the header is where you move the DIV from:
document.getElementById("dev-header").onmousedown = dragMouseDown
} else {
// otherwise, move the DIV from anywhere inside the DIV:
element.onmousedown = dragMouseDown
}
function dragMouseDown(e) {
e = e || window.event
e.preventDefault()
// get the mouse cursor position at startup:
pos3 = e.clientX
pos4 = e.clientY
document.onmouseup = closeDragElement
// call a function whenever the cursor moves:
document.onmousemove = elementDrag
}
function elementDrag(e) {
e = e || window.event
e.preventDefault()
pos1 = pos3 - e.clientX
pos2 = pos4 - e.clientY
pos3 = e.clientX
pos4 = e.clientY
element.style.top = element.offsetTop - pos2 + "px"
element.style.left = element.offsetLeft - pos1 + "px"
}
function closeDragElement() {
document.onmouseup = null
document.onmousemove = null
}
}
},
mounted() {
this.drag(document.getElementById("dev-overlay"))
}
}
</script>
<style scoped></style>

View File

@ -174,11 +174,110 @@
<v-row v-if="!loading" @drop="handleDrag" no-gutters>
<v-col class="flex-grow-1 flex-shrink-1 pb-0" id="chat-col">
<v-card
class="d-flex flex-column fill-height rounded-0 mb-n3"
class="d-flex flex-column-reverse fill-height rounded-0 mb-n3 chat-col"
style="overflow: auto; height: calc(100vh - 24px - 40px)"
color="card"
elevation="0"
>
<v-card-text>
<v-toolbar
@click="jumpToMessage(replying?.id)"
elevation="0"
height="35"
color="card"
v-if="replying"
style="cursor: pointer; overflow: hidden"
>
<v-icon class="mr-2">mdi-reply</v-icon>
<v-avatar size="24" class="mr-2">
<v-img
:src="
$store.state.baseURL +
'/usercontent/' +
replying.user.avatar
"
v-if="replying.user.avatar"
class="elevation-1"
/>
<v-icon v-else class="elevation-1"> mdi-account </v-icon>
</v-avatar>
<template v-if="replying.attachments.length">
<v-icon class="mr-2">mdi-file-image</v-icon>
</template>
<template v-if="!replying.content && replying.attachments.length">
Click to view attachment
</template>
{{ replying.content.substring(0, 100) }}
<v-spacer></v-spacer>
<v-btn icon @click="replying = null" class="mr-2" small>
<v-icon> mdi-close </v-icon>
</v-btn>
</v-toolbar>
<v-fade-transition v-model="avoidAutoScroll">
<v-toolbar
height="22"
color="toolbar"
elevation="0"
style="
border-radius: 20px 20px 0 0;
cursor: pointer;
position: relative;
top: -30px;
margin-bottom: -27px;
z-index: 20;
"
width="100%"
@click="forceBottom"
v-if="avoidAutoScroll"
>
<div>
<v-icon size="16px"> mdi-arrow-down </v-icon>
Jump to bottom...
</div>
</v-toolbar>
</v-fade-transition>
<v-fade-transition
v-model="usersTyping.length"
v-if="$vuetify.breakpoint.mobile"
>
<div
style="
border-radius: 0 0 20px 20px;
position: relative;
top: -30px;
margin-bottom: -22px;
"
v-if="usersTyping.length"
>
{{ usersTyping.map((user) => getName(user)).join(", ") }}
{{ usersTyping.length > 1 ? " are" : " is" }} typing...
</div>
</v-fade-transition>
<CommsInput
:chat="chat"
:replying="replying"
:editLastMessage="editLastMessage"
:autoScroll="autoScroll"
:endSend="endSend"
></CommsInput>
<v-fade-transition
v-model="usersTyping.length"
v-if="!$vuetify.breakpoint.mobile"
>
<div
style="
border-radius: 0 0 20px 20px;
position: absolute;
margin-top: -2px;
bottom: 1px;
"
v-if="usersTyping.length"
>
{{ usersTyping.map((user) => getName(user)).join(", ") }}
{{ usersTyping.length > 1 ? " are" : " is" }} typing...
</div>
</v-fade-transition>
</v-card-text>
<v-card-text class="flex-grow-1 overflow-y-auto" id="message-list">
<v-card-title
v-if="
@ -312,104 +411,6 @@
</span>
</v-tooltip>
</v-card-text>
<v-card-text>
<v-toolbar
@click="jumpToMessage(replying?.id)"
elevation="0"
height="35"
color="card"
v-if="replying"
style="cursor: pointer; overflow: hidden"
>
<v-icon class="mr-2">mdi-reply</v-icon>
<v-avatar size="24" class="mr-2">
<v-img
:src="
$store.state.baseURL +
'/usercontent/' +
replying.user.avatar
"
v-if="replying.user.avatar"
class="elevation-1"
/>
<v-icon v-else class="elevation-1"> mdi-account </v-icon>
</v-avatar>
<template v-if="replying.attachments.length">
<v-icon class="mr-2">mdi-file-image</v-icon>
</template>
<template v-if="!replying.content && replying.attachments.length">
Click to view attachment
</template>
{{ replying.content.substring(0, 100) }}
<v-spacer></v-spacer>
<v-btn icon @click="replying = null" class="mr-2" small>
<v-icon> mdi-close </v-icon>
</v-btn>
</v-toolbar>
<v-fade-transition v-model="avoidAutoScroll">
<v-toolbar
height="22"
color="toolbar"
elevation="0"
style="
border-radius: 20px 20px 0 0;
cursor: pointer;
position: relative;
top: -30px;
margin-bottom: -27px;
"
width="100%"
@click="forceBottom"
v-if="avoidAutoScroll"
>
<div>
<v-icon size="16px"> mdi-arrow-down </v-icon>
Jump to bottom...
</div>
</v-toolbar>
</v-fade-transition>
<v-fade-transition
v-model="usersTyping.length"
v-if="$vuetify.breakpoint.mobile"
>
<div
style="
border-radius: 0 0 20px 20px;
position: relative;
top: -30px;
margin-bottom: -22px;
"
v-if="usersTyping.length"
>
{{ usersTyping.map((user) => getName(user)).join(", ") }}
{{ usersTyping.length > 1 ? " are" : " is" }} typing...
</div>
</v-fade-transition>
<CommsInput
:chat="chat"
:replying="replying"
:editLastMessage="editLastMessage"
:autoScroll="autoScroll"
:endSend="endSend"
></CommsInput>
<v-fade-transition
v-model="usersTyping.length"
v-if="!$vuetify.breakpoint.mobile"
>
<div
style="
border-radius: 0 0 20px 20px;
position: absolute;
margin-top: -2px;
bottom: 1px;
"
v-if="usersTyping.length"
>
{{ usersTyping.map((user) => getName(user)).join(", ") }}
{{ usersTyping.length > 1 ? " are" : " is" }} typing...
</div>
</v-fade-transition>
</v-card-text>
</v-card>
</v-col>
<v-col
@ -1156,20 +1157,24 @@ export default {
}
})
this.$socket.on("readReceipt", (data) => {
if (
data.messageId &&
data.chatId === this.chat.chatId &&
this.messages?.length
) {
this.messages.forEach((message) => {
message.readReceipts = message.readReceipts.filter(
(readReceipt) => readReceipt.id !== data.id
)
})
this.messages
.find((message) => message.id === data.messageId)
.readReceipts?.push(data)
this.autoScroll()
try {
if (
data.messageId &&
data.chatId === this.chat.chatId &&
this.messages?.length
) {
this.messages.forEach((message) => {
message.readReceipts = message.readReceipts.filter(
(readReceipt) => readReceipt.id !== data.id
)
})
this.messages
.find((message) => message.id === data.messageId)
.readReceipts?.push(data)
this.autoScroll()
}
} catch (e) {
console.log("Read receipt error", e)
}
})
this.$socket.on("message", (message) => {