implement sending image attachment via web ui
This commit is contained in:
@@ -257,8 +257,34 @@
|
|||||||
<!-- message composer -->
|
<!-- message composer -->
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
|
<!-- image attachment -->
|
||||||
|
<div v-if="newMessageImage" class="mb-2">
|
||||||
|
<div class="w-32 h-32 rounded shadow border relative overflow-hidden">
|
||||||
|
|
||||||
|
<!-- image preview -->
|
||||||
|
<img v-if="newMessageImageUrl" :src="newMessageImageUrl" class="w-full h-full"/>
|
||||||
|
|
||||||
|
<!-- remove button (top right) -->
|
||||||
|
<div class="absolute top-0 right-0 p-1">
|
||||||
|
<div @click="removeImageAttachment" href="javascript:void(0)" class="cursor-pointer">
|
||||||
|
<div class="flex text-gray-700 bg-gray-100 hover:bg-gray-200 p-1 rounded-full">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4">
|
||||||
|
<path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- image size (bottom left) -->
|
||||||
|
<div class="absolute bottom-0 left-0 p-1">
|
||||||
|
<div class="bg-gray-100 rounded border text-sm px-1">{{ formatBytes(newMessageImage.size) }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- file attachments -->
|
<!-- file attachments -->
|
||||||
<div class="mb-2">
|
<div v-if="newMessageFiles.length > 0" class="mb-2">
|
||||||
<div class="flex flex-wrap gap-1">
|
<div class="flex flex-wrap gap-1">
|
||||||
<div v-for="file in newMessageFiles" class="flex border border-gray-300 rounded text-gray-700 divide-x divide-gray-300 overflow-hidden">
|
<div v-for="file in newMessageFiles" class="flex border border-gray-300 rounded text-gray-700 divide-x divide-gray-300 overflow-hidden">
|
||||||
<div class="my-auto px-1">
|
<div class="my-auto px-1">
|
||||||
@@ -281,7 +307,7 @@
|
|||||||
<div class="flex mt-2">
|
<div class="flex mt-2">
|
||||||
|
|
||||||
<!-- add files -->
|
<!-- add files -->
|
||||||
<button @click="addFilesToMessage" type="button" class="my-auto inline-flex items-center gap-x-1 rounded-md bg-gray-500 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-gray-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500">
|
<button @click="addFilesToMessage" type="button" class="my-auto mr-1 inline-flex items-center gap-x-1 rounded-md bg-gray-500 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-gray-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-5 h-5">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-5 h-5">
|
||||||
<path fill-rule="evenodd" d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875ZM12.75 12a.75.75 0 0 0-1.5 0v2.25H9a.75.75 0 0 0 0 1.5h2.25V18a.75.75 0 0 0 1.5 0v-2.25H15a.75.75 0 0 0 0-1.5h-2.25V12Z" clip-rule="evenodd" />
|
<path fill-rule="evenodd" d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875ZM12.75 12a.75.75 0 0 0-1.5 0v2.25H9a.75.75 0 0 0 0 1.5h2.25V18a.75.75 0 0 0 1.5 0v-2.25H15a.75.75 0 0 0 0-1.5h-2.25V12Z" clip-rule="evenodd" />
|
||||||
<path d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z" />
|
<path d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z" />
|
||||||
@@ -289,6 +315,14 @@
|
|||||||
<span class="ml-1">Add Files</span>
|
<span class="ml-1">Add Files</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- add image -->
|
||||||
|
<button @click="addImageToMessage" type="button" class="my-auto mr-1 inline-flex items-center gap-x-1 rounded-md bg-gray-500 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-gray-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-5 h-5">
|
||||||
|
<path fill-rule="evenodd" d="M1.5 6a2.25 2.25 0 0 1 2.25-2.25h16.5A2.25 2.25 0 0 1 22.5 6v12a2.25 2.25 0 0 1-2.25 2.25H3.75A2.25 2.25 0 0 1 1.5 18V6ZM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0 0 21 18v-1.94l-2.69-2.689a1.5 1.5 0 0 0-2.12 0l-.88.879.97.97a.75.75 0 1 1-1.06 1.06l-5.16-5.159a1.5 1.5 0 0 0-2.12 0L3 16.061Zm10.125-7.81a1.125 1.125 0 1 1 2.25 0 1.125 1.125 0 0 1-2.25 0Z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
<span class="ml-1">Add Image</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- send message -->
|
<!-- send message -->
|
||||||
<button @click="sendMessage" type="button" class="ml-auto my-auto inline-flex items-center gap-x-1 rounded-md bg-blue-500 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500">
|
<button @click="sendMessage" type="button" class="ml-auto my-auto inline-flex items-center gap-x-1 rounded-md bg-blue-500 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500">
|
||||||
Send
|
Send
|
||||||
@@ -319,6 +353,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- hidden file input for selecting files -->
|
<!-- hidden file input for selecting files -->
|
||||||
|
<input ref="image-input" @change="onImageInputChange" type="file" accept="image/*" style="display:none"/>
|
||||||
<input ref="file-input" @change="onFileInputChange" type="file" multiple style="display:none"/>
|
<input ref="file-input" @change="onFileInputChange" type="file" multiple style="display:none"/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -331,6 +366,8 @@
|
|||||||
autoReconnectWebsocket: true,
|
autoReconnectWebsocket: true,
|
||||||
|
|
||||||
newMessageText: "",
|
newMessageText: "",
|
||||||
|
newMessageImage: null,
|
||||||
|
newMessageImageUrl: null,
|
||||||
newMessageFiles: [],
|
newMessageFiles: [],
|
||||||
isSendingMessage: false,
|
isSendingMessage: false,
|
||||||
autoScrollOnNewMessage: true,
|
autoScrollOnNewMessage: true,
|
||||||
@@ -593,6 +630,14 @@
|
|||||||
fields["file_attachments"] = fileAttachments;
|
fields["file_attachments"] = fileAttachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add image attachment
|
||||||
|
if(this.newMessageImage){
|
||||||
|
fields["image"] = {
|
||||||
|
"image_type": this.newMessageImage.type,
|
||||||
|
"image_bytes": this.arrayBufferToBase64(await this.newMessageImage.arrayBuffer()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// send message to reticulum via websocket
|
// send message to reticulum via websocket
|
||||||
this.ws.send(JSON.stringify({
|
this.ws.send(JSON.stringify({
|
||||||
"type": "lxmf.delivery",
|
"type": "lxmf.delivery",
|
||||||
@@ -605,7 +650,10 @@
|
|||||||
|
|
||||||
// clear message inputs
|
// clear message inputs
|
||||||
this.newMessageText = "";
|
this.newMessageText = "";
|
||||||
|
this.newMessageImage = null;
|
||||||
|
this.newMessageImageUrl = null;
|
||||||
this.newMessageFiles = [];
|
this.newMessageFiles = [];
|
||||||
|
this.clearImageInput();
|
||||||
this.clearFileInput();
|
this.clearFileInput();
|
||||||
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@@ -854,6 +902,36 @@
|
|||||||
return newMessageFile !== file;
|
return newMessageFile !== file;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
addImageToMessage: function() {
|
||||||
|
this.$refs["image-input"].click();
|
||||||
|
},
|
||||||
|
onImageInputChange: function(event) {
|
||||||
|
if(event.target.files.length > 0){
|
||||||
|
|
||||||
|
// update selected file
|
||||||
|
this.newMessageImage = event.target.files[0];
|
||||||
|
|
||||||
|
// update image url when file is read
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
fileReader.onload = (event) => {
|
||||||
|
this.newMessageImageUrl = event.target.result
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert image to data url
|
||||||
|
fileReader.readAsDataURL(this.newMessageImage);
|
||||||
|
|
||||||
|
// clear image input to allow selecting the same file after user removed it
|
||||||
|
this.clearImageInput();
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearImageInput: function() {
|
||||||
|
this.$refs["image-input"].value = null;
|
||||||
|
},
|
||||||
|
removeImageAttachment: function() {
|
||||||
|
this.newMessageImage = null;
|
||||||
|
this.newMessageImageUrl = null;
|
||||||
|
},
|
||||||
formatBytes: function(bytes) {
|
formatBytes: function(bytes) {
|
||||||
|
|
||||||
if(bytes === 0){
|
if(bytes === 0){
|
||||||
|
|||||||
Reference in New Issue
Block a user