mirror of
https://github.com/Troplo/Colubrina.git
synced 2024-11-25 04:36:44 +11:00
1.0.30
This commit is contained in:
parent
88012b1930
commit
87976eac86
5 changed files with 243 additions and 114 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "colubrina",
|
"name": "colubrina",
|
||||||
"version": "1.0.29",
|
"version": "1.0.30",
|
||||||
"description": "Simple instant communication.",
|
"description": "Simple instant communication.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "Troplo <troplo@troplo.com>",
|
"author": "Troplo <troplo@troplo.com>",
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
$vuetify.theme.themes[$vuetify.theme.dark ? 'dark' : 'light'].bg
|
$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-overlay :value="$store.state.site.loading">
|
||||||
<v-progress-circular indeterminate size="64"></v-progress-circular>
|
<v-progress-circular indeterminate size="64"></v-progress-circular>
|
||||||
</v-overlay>
|
</v-overlay>
|
||||||
|
@ -454,10 +455,12 @@
|
||||||
import AjaxErrorHandler from "@/lib/errorHandler"
|
import AjaxErrorHandler from "@/lib/errorHandler"
|
||||||
import { VueFinalModal } from "vue-final-modal"
|
import { VueFinalModal } from "vue-final-modal"
|
||||||
import Header from "@/components/Header"
|
import Header from "@/components/Header"
|
||||||
|
import DevOverlay from "@/components/DevOverlay"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: {
|
components: {
|
||||||
|
DevOverlay,
|
||||||
VueFinalModal,
|
VueFinalModal,
|
||||||
Header,
|
Header,
|
||||||
editor: require("vue2-ace-editor")
|
editor: require("vue2-ace-editor")
|
||||||
|
|
|
@ -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-v-list-height {
|
||||||
max-height: 10px;
|
max-height: 10px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
91
frontend/src/components/DevOverlay.vue
Normal file
91
frontend/src/components/DevOverlay.vue
Normal 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>
|
|
@ -174,11 +174,110 @@
|
||||||
<v-row v-if="!loading" @drop="handleDrag" no-gutters>
|
<v-row v-if="!loading" @drop="handleDrag" no-gutters>
|
||||||
<v-col class="flex-grow-1 flex-shrink-1 pb-0" id="chat-col">
|
<v-col class="flex-grow-1 flex-shrink-1 pb-0" id="chat-col">
|
||||||
<v-card
|
<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)"
|
style="overflow: auto; height: calc(100vh - 24px - 40px)"
|
||||||
color="card"
|
color="card"
|
||||||
elevation="0"
|
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-text class="flex-grow-1 overflow-y-auto" id="message-list">
|
||||||
<v-card-title
|
<v-card-title
|
||||||
v-if="
|
v-if="
|
||||||
|
@ -312,104 +411,6 @@
|
||||||
</span>
|
</span>
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
</v-card-text>
|
</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-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col
|
<v-col
|
||||||
|
@ -1156,20 +1157,24 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.$socket.on("readReceipt", (data) => {
|
this.$socket.on("readReceipt", (data) => {
|
||||||
if (
|
try {
|
||||||
data.messageId &&
|
if (
|
||||||
data.chatId === this.chat.chatId &&
|
data.messageId &&
|
||||||
this.messages?.length
|
data.chatId === this.chat.chatId &&
|
||||||
) {
|
this.messages?.length
|
||||||
this.messages.forEach((message) => {
|
) {
|
||||||
message.readReceipts = message.readReceipts.filter(
|
this.messages.forEach((message) => {
|
||||||
(readReceipt) => readReceipt.id !== data.id
|
message.readReceipts = message.readReceipts.filter(
|
||||||
)
|
(readReceipt) => readReceipt.id !== data.id
|
||||||
})
|
)
|
||||||
this.messages
|
})
|
||||||
.find((message) => message.id === data.messageId)
|
this.messages
|
||||||
.readReceipts?.push(data)
|
.find((message) => message.id === data.messageId)
|
||||||
this.autoScroll()
|
.readReceipts?.push(data)
|
||||||
|
this.autoScroll()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Read receipt error", e)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.$socket.on("message", (message) => {
|
this.$socket.on("message", (message) => {
|
||||||
|
|
Loading…
Reference in a new issue