feat: implement multiline message box
All checks were successful
ci/woodpecker/push/build-and-publish Pipeline was successful
ci/woodpecker/pr/build-and-publish Pipeline was successful

This commit is contained in:
Twig 2025-07-09 16:34:39 +02:00
parent f1bec945fe
commit e58809b424
No known key found for this signature in database

View file

@ -14,11 +14,14 @@
<Icon name="lucide:file-plus-2" /> <Icon name="lucide:file-plus-2" />
</span> </span>
</div> </div>
<textarea v-model="messageInput" id="message-box-input" ref="messageInputField"
class="rounded-corners" type="text" name="message-input" <div id="message-textarea">
autocomplete="off" contenteditable="true" spellcheck="true" <div id="message-textbox-input" class=""
@keydown="handleMessageKeyDown"> role="textbox" ref="messageTextboxInput"
</textarea> autocorrect="off" spellcheck="true" contenteditable="true"
@keydown="handleTextboxKeyDown" @input="handleTextboxInput">
</div>
</div>
<div id="message-box-right-elements"> <div id="message-box-right-elements">
<button class="message-box-button" type="submit"> <button class="message-box-button" type="submit">
@ -120,19 +123,38 @@ function pushMessage(message: MessageResponse) {
messages.value.push(message); messages.value.push(message);
} }
function handleMessageKeyDown(event: KeyboardEvent) { function handleTextboxKeyDown(event: KeyboardEvent) {
if (event.key === "Enter" && event.shiftKey) { if (event.key === "Enter" && event.shiftKey && messageTextboxInput.value) {
event.preventDefault(); // this enters a newline, due to not preventing default
messageInput.value += "\n"
} else if (event.key === "Enter") { } else if (event.key === "Enter") {
// <send message> event.preventDefault()
sendMessage(event)
}
adjustTextboxHeight()
}
function handleTextboxInput() {
if (messageTextboxInput.value) {
messageInput.value = messageTextboxInput.value.innerText;
}
adjustTextboxHeight()
}
// this technically uses pixel units, but it's still set using dynamic units
function adjustTextboxHeight() {
if (messageTextboxInput.value && messageTextboxDisplay.value) {
messageTextboxInput.value.style.height = "auto"
messageTextboxInput.value.style.height = `${messageTextboxInput.value.scrollHeight}px`
} }
} }
const messages = ref<MessageResponse[]>([]); const messages = ref<MessageResponse[]>([]);
const messageInput = ref<string>(); const messageInput = ref<string>("");
const messagesElement = ref<HTMLDivElement>(); const messagesElement = ref<HTMLDivElement>();
const messageInputField = ref<HTMLTextAreaElement>(); const messageTextboxInput = ref<HTMLDivElement>();
const messageTextboxDisplay = ref<HTMLDivElement>();
if (messagesRes) messages.value = messagesRes; if (messagesRes) messages.value = messagesRes;
@ -180,14 +202,21 @@ if (accessToken && apiBase) {
function sendMessage(e: Event) { function sendMessage(e: Event) {
e.preventDefault(); e.preventDefault();
const message = { if (messageInput.value && messageInput.value.trim() !== "") {
message: messageInput.value const message = {
} message: messageInput.value.trim().replace(/\n/g, "<br>") // trim, and replace \n with <br>
console.log("message:", message); }
if (message.message) {
console.log("message:", message);
ws.send(JSON.stringify(message)); ws.send(JSON.stringify(message));
messageInput.value = "";
console.log("MESSAGE SENT!!!"); // reset input field
messageInput.value = ""
if (messageTextboxInput.value) {
messageTextboxInput.value.innerText = ""
}
adjustTextboxHeight()
} }
} }
@ -278,35 +307,42 @@ router.beforeEach((to, from, next) => {
padding-left: 2%; padding-left: 2%;
padding-right: 2%; padding-right: 2%;
min-height: 5em; align-items: center;
max-height: 50%;
flex-grow: 1; color: var(--text-color);
border: 1px solid var(--padding-color); border: 1px solid var(--padding-color);
background-color: var(--chatbox-background-color); background-color: var(--chatbox-background-color);
} }
#message-form { #message-form {
height: 100%;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: .5em; gap: .55em;
} }
#message-box-input { #message-textarea {
flex-grow: 1; flex-grow: 1;
min-height: 2.35em;
}
color: inherit; #message-textbox-input {
font: inherit; width: 100%;
max-height: 50dvh;
padding: 0.5em 0;
user-select: text;
font-family: inherit;
font-size: inherit;
line-height: normal;
border: none; border: none;
background-color: #40404000; /* completely transparent colour */ background-color: #40404000; /* completely transparent colour */
box-sizing: border-box; text-align: left;
display: inline-block; word-break: break-word;
overflow-wrap: break-word;
overflow: auto; overflow-y: auto;
resize: none;
} }
#message-box-left-elements, #message-box-right-elements { #message-box-left-elements, #message-box-right-elements {