Compare commits

..

3 Commits

Author SHA1 Message Date
Sam Hoffman
63cf089d27 unwelcomed to Vuetify 2026-01-13 00:34:54 -05:00
Sam Hoffman
03e95a2c69 allow changing nicks. store nick/avatar in localStorage 2026-01-13 00:34:45 -05:00
Sam Hoffman
f86b48f43e fix auto scroll in chat history 2026-01-13 00:33:53 -05:00
4 changed files with 74 additions and 32 deletions

View File

@@ -1,10 +1,10 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Welcome to Vuetify 3</title> <title>IrChad</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -1,5 +1,5 @@
<script setup> <script setup>
import { computed } from "vue"; import { computed, watch, useTemplateRef } from "vue";
import { useIRCStore } from "@/stores/irc"; import { useIRCStore } from "@/stores/irc";
const props = defineProps(["messages", "me"]); const props = defineProps(["messages", "me"]);
@@ -15,14 +15,26 @@ const timeFormatter = new Intl.DateTimeFormat("en-US", {
minute: "2-digit", minute: "2-digit",
hour12: true, hour12: true,
}); });
function formatTime(ts) { function formatTime(ts) {
const date = new Date(ts); const date = new Date(ts);
return timeFormatter.format(date); return timeFormatter.format(date);
} }
const chatHistory = useTemplateRef("chat-scrollback");
watch(
() => props.messages,
() =>
nextTick(() => {
chatHistory.value.scrollTop = chatHistory.value.scrollHeight;
}),
{ deep: true },
);
</script> </script>
<template> <template>
<v-sheet class="message-list d-flex"> <v-sheet ref="chat-history" class="message-list d-flex">
<div ref="chat-scrollback">
<v-list> <v-list>
<v-list-item <v-list-item
v-for="msg in messagesReverse" v-for="msg in messagesReverse"
@@ -31,7 +43,7 @@ function formatTime(ts) {
> >
<v-list-item-title> <v-list-item-title>
<span <span
class="message-nick" class="message-nick font-weight-bold"
:class="{ 'text-primary': me === msg.nick }" :class="{ 'text-primary': me === msg.nick }"
> >
{{ msg.nick }} {{ msg.nick }}
@@ -40,11 +52,10 @@ function formatTime(ts) {
formatTime(msg.time) formatTime(msg.time)
}}</span> }}</span>
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle>
{{ msg.message }} {{ msg.message }}
</v-list-item-subtitle>
</v-list-item> </v-list-item>
</v-list> </v-list>
</div>
</v-sheet> </v-sheet>
</template> </template>

View File

@@ -4,11 +4,12 @@ import { useIRCStore } from "@/stores/irc";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
const { selfAvatar } = storeToRefs(useIRCStore()); const { selfAvatar } = storeToRefs(useIRCStore());
const { client, clientInfo, setAvatar, setNick } = useIRCStore(); const { clientInfo, setAvatar, setNick } = useIRCStore();
const avatarDialog = ref(false); const avatarDialog = ref(false);
const newNick = ref(); const newNick = ref();
function changeAvatar() { function changeAvatar() {
newNick.value = clientInfo.nick;
avatarDialog.value = true; avatarDialog.value = true;
} }
@@ -16,14 +17,13 @@ function submitAvatar() {
setAvatar(selfAvatar.value); setAvatar(selfAvatar.value);
avatarDialog.value = false; avatarDialog.value = false;
if (newNick.value && clientInfo.nick !== newNick.value) { if (newNick.value && clientInfo.nick !== newNick.value) {
console.log("nick changed"); setNick(newNick.value);
client.changeNick(newNick.value);
} }
} }
</script> </script>
<template> <template>
<v-dialog v-model="avatarDialog"> <v-dialog v-model="avatarDialog" max-width="800px">
<v-card title="Edit Profile"> <v-card title="Edit Profile">
<v-card-text> <v-card-text>
<v-text-field v-model="selfAvatar" label="Avatar URL" /> <v-text-field v-model="selfAvatar" label="Avatar URL" />

View File

@@ -15,9 +15,34 @@ export const useIRCStore = defineStore("irc", () => {
const selfAvatar = ref("https://placekittens.com/128/128"); const selfAvatar = ref("https://placekittens.com/128/128");
loadPrefs();
function setAvatar(v) { function setAvatar(v) {
selfAvatar.value = v; selfAvatar.value = v;
client.raw(`METADATA * SET avatar ${selfAvatar.value}`); client.raw(`METADATA * SET avatar ${selfAvatar.value}`);
storePrefs();
}
function loadPrefs() {
const prefs = JSON.parse(localStorage.getItem("prefs"));
if (!prefs) return;
if (prefs.avatar) {
selfAvatar.value = prefs.avatar;
}
if (prefs.nick) {
clientInfo.value.nick = prefs.nick;
}
}
function storePrefs() {
localStorage.setItem(
"prefs",
JSON.stringify({
nick: clientInfo.value.nick,
avatar: selfAvatar.value,
}),
);
} }
function setNick(v) { function setNick(v) {
@@ -56,6 +81,7 @@ export const useIRCStore = defineStore("irc", () => {
function connect() { function connect() {
client.requestCap("draft/metadata-2"); client.requestCap("draft/metadata-2");
client.requestCap("echo-message"); client.requestCap("echo-message");
client.requestCap("chathistory");
const tls = location.protocol === "https:"; const tls = location.protocol === "https:";
client.connect({ client.connect({
...clientInfo.value, ...clientInfo.value,
@@ -104,12 +130,15 @@ export const useIRCStore = defineStore("irc", () => {
client.on("nick", function ({ nick, new_nick }) { client.on("nick", function ({ nick, new_nick }) {
if (nick === clientInfo.value.nick) { if (nick === clientInfo.value.nick) {
clientInfo.value.nick = new_nick; clientInfo.value.nick = new_nick;
storePrefs();
} }
for (let buff of Object.values(buffers.value)) { for (let buff of Object.values(buffers.value)) {
const idx = buff.users.findIndex((u) => u.nick === nick); const idx = buff.users.findIndex((u) => u.nick === nick);
if (idx === -1) continue; if (idx === -1) continue;
buff.users[idx].nick = new_nick; buff.users[idx].nick = new_nick;
} }
metadata.value[new_nick] = { ...metadata.value[nick] };
delete metadata.value[nick];
}); });
client.on("unknown command", function (ircCommand) { client.on("unknown command", function (ircCommand) {
@@ -138,6 +167,7 @@ export const useIRCStore = defineStore("irc", () => {
client.on("message", function (message) { client.on("message", function (message) {
let buffer; let buffer;
if (message.nick === "HistServ") return;
if (isMe(message.target)) { if (isMe(message.target)) {
buffer = getBuffer(message.nick); buffer = getBuffer(message.nick);
} else { } else {
@@ -158,6 +188,7 @@ export const useIRCStore = defineStore("irc", () => {
if (!activeBufferName.value) { if (!activeBufferName.value) {
activeBufferName.value = channel; activeBufferName.value = channel;
} }
client.raw("CHATHISTORY LATEST " + channel + " * 200");
return; return;
} }