lots of things
This commit is contained in:
@@ -1,7 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app>
|
<v-app>
|
||||||
<Login v-if="!ircStore.connected" />
|
<router-view />
|
||||||
<Chat v-else />
|
|
||||||
|
<!-- <Login v-if="!ircStore.connected" /> -->
|
||||||
|
<!-- <Chat v-else /> -->
|
||||||
|
<!-- <v-dialog max-width="450px" v-model="showRegistration"> -->
|
||||||
|
<!-- <Register @success="showRegistration = false" /> -->
|
||||||
|
<!-- </v-dialog> -->
|
||||||
</v-app>
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -9,6 +14,10 @@
|
|||||||
import { useIRCStore } from "@/stores/irc";
|
import { useIRCStore } from "@/stores/irc";
|
||||||
import Chat from "@/components/Chat.vue";
|
import Chat from "@/components/Chat.vue";
|
||||||
import Login from "@/components/Login.vue";
|
import Login from "@/components/Login.vue";
|
||||||
|
import Register from "@/components/Register.vue";
|
||||||
|
import { useAccountStore } from "./stores/accountStore";
|
||||||
|
|
||||||
const ircStore = useIRCStore();
|
const ircStore = useIRCStore();
|
||||||
|
const accountStore = useAccountStore();
|
||||||
|
const { showRegistration } = storeToRefs(accountStore);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const accountStore = useAccountStore();
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="d-flex flex-row" style="height: 100vh">
|
<div class="d-flex flex-row" style="height: 100vh">
|
||||||
|
<router-view />
|
||||||
<v-sheet border class="buffers">
|
<v-sheet border class="buffers">
|
||||||
<UserCard />
|
<UserCard />
|
||||||
<v-divider />
|
<v-divider />
|
||||||
@@ -27,16 +28,10 @@ const accountStore = useAccountStore();
|
|||||||
:me="accountStore.account.nick"
|
:me="accountStore.account.nick"
|
||||||
/>
|
/>
|
||||||
<v-sheet>
|
<v-sheet>
|
||||||
<!-- <v-text-field -->
|
<InputBuffer
|
||||||
<!-- variant="outlined" -->
|
@raw="(txt: string) => ircStore.client.raw(txt)"
|
||||||
<!-- :placeholder="`Message ${store.activeBufferName}`" -->
|
@send="ircStore.sendActiveBuffer"
|
||||||
<!-- v-model="inputBuffer" -->
|
/>
|
||||||
<!-- hide-details -->
|
|
||||||
<!-- class="ma-2" -->
|
|
||||||
<!-- @keydown.enter.exact.prevent="send" -->
|
|
||||||
<!-- /> -->
|
|
||||||
|
|
||||||
<InputBuffer @send="ircStore.sendActiveBuffer" />
|
|
||||||
</v-sheet>
|
</v-sheet>
|
||||||
</div>
|
</div>
|
||||||
<v-sheet class="user-list h-100" border>
|
<v-sheet class="user-list h-100" border>
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useIRCStore } from "@/stores/irc";
|
import { useIRCStore } from "@/stores/irc";
|
||||||
import { useBufferStore } from "@/stores/bufferStore";
|
import { useBufferStore } from "@/stores/bufferStore";
|
||||||
const emit = defineEmits(["send"]);
|
import { useAccountStore } from "@/stores/accountStore";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const emit = defineEmits(["send", "raw"]);
|
||||||
|
|
||||||
const store = useIRCStore();
|
const store = useIRCStore();
|
||||||
|
const accountStore = useAccountStore();
|
||||||
|
const { showRegistration } = storeToRefs(accountStore);
|
||||||
|
const router = useRouter();
|
||||||
const bufferStore = useBufferStore();
|
const bufferStore = useBufferStore();
|
||||||
const text = ref();
|
const text = ref();
|
||||||
const menu = ref({
|
const menu = ref({
|
||||||
@@ -15,7 +21,7 @@ const menu = ref({
|
|||||||
const menuList = ref({
|
const menuList = ref({
|
||||||
density: "compact",
|
density: "compact",
|
||||||
slim: true,
|
slim: true,
|
||||||
items: [],
|
items: [] as any[],
|
||||||
itemTitle: "title",
|
itemTitle: "title",
|
||||||
itemValue: "value",
|
itemValue: "value",
|
||||||
selected: [],
|
selected: [],
|
||||||
@@ -30,18 +36,26 @@ const completionPos = ref(0);
|
|||||||
function clickItem() {}
|
function clickItem() {}
|
||||||
function send() {
|
function send() {
|
||||||
if (!text.value) return;
|
if (!text.value) return;
|
||||||
|
|
||||||
|
if (text.value.slice(0, 2) === "//") {
|
||||||
|
emit("raw", text.value.substring(2));
|
||||||
|
} else if (text.value[0] === "/") {
|
||||||
|
router.push({ path: "/register" });
|
||||||
|
} else {
|
||||||
emit("send", text.value);
|
emit("send", text.value);
|
||||||
|
}
|
||||||
|
|
||||||
menu.value.open = false;
|
menu.value.open = false;
|
||||||
text.value = "";
|
text.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterUsers(s) {
|
function filterUsers(s: string) {
|
||||||
if (store.activeBuffer) {
|
if (store.activeBuffer) {
|
||||||
return store.activeBuffer.users.filter((u) => u.nick.startsWith(s));
|
return store.activeBuffer.users.filter((u) => u.nick.startsWith(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function trigger(ev) {
|
function trigger(ev: KeyboardEvent) {
|
||||||
const input = ev.target;
|
const input = ev.target;
|
||||||
const cursor = input.selectionStart;
|
const cursor = input.selectionStart;
|
||||||
cursorPos.value = cursor;
|
cursorPos.value = cursor;
|
||||||
@@ -49,7 +63,18 @@ function trigger(ev) {
|
|||||||
|
|
||||||
const textBefore = text.slice(0, cursor);
|
const textBefore = text.slice(0, cursor);
|
||||||
const mentionMatch = textBefore.match(/@(\w*)$/);
|
const mentionMatch = textBefore.match(/@(\w*)$/);
|
||||||
if (mentionMatch) {
|
if (text[0] === "/") {
|
||||||
|
menu.value.open = true;
|
||||||
|
menuList.value.items = [
|
||||||
|
{
|
||||||
|
title: "register",
|
||||||
|
value: "register",
|
||||||
|
cmd: () => {
|
||||||
|
showRegistration.value = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else if (mentionMatch) {
|
||||||
menu.value.open = true;
|
menu.value.open = true;
|
||||||
menuList.value.items = filterUsers(mentionMatch[1]);
|
menuList.value.items = filterUsers(mentionMatch[1]);
|
||||||
menuList.value.itemTitle = "nick";
|
menuList.value.itemTitle = "nick";
|
||||||
|
|||||||
@@ -2,15 +2,21 @@
|
|||||||
import { useAccountStore } from "@/stores/accountStore";
|
import { useAccountStore } from "@/stores/accountStore";
|
||||||
import { useIRCStore } from "@/stores/irc";
|
import { useIRCStore } from "@/stores/irc";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
const accountStore = useAccountStore();
|
const accountStore = useAccountStore();
|
||||||
const ircStore = useIRCStore();
|
const ircStore = useIRCStore();
|
||||||
|
|
||||||
const { account } = storeToRefs(accountStore);
|
const { account } = storeToRefs(accountStore);
|
||||||
const withAccount = ref(false);
|
const withAccount = ref(false);
|
||||||
const form = ref(false);
|
const form = ref(false);
|
||||||
|
const connecting = ref(false);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
function login() {
|
function login() {
|
||||||
ircStore.connect();
|
ircStore.connect();
|
||||||
|
connecting.value = true;
|
||||||
|
router.push({ name: "Chat" });
|
||||||
}
|
}
|
||||||
|
|
||||||
function required(v: any) {
|
function required(v: any) {
|
||||||
@@ -48,7 +54,13 @@ function required(v: any) {
|
|||||||
<v-checkbox v-model="withAccount" label="Login with an account" />
|
<v-checkbox v-model="withAccount" label="Login with an account" />
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-btn type="submit" color="success" :disabled="!form">Connect</v-btn>
|
<v-btn
|
||||||
|
:loading="connecting"
|
||||||
|
type="submit"
|
||||||
|
color="success"
|
||||||
|
:disabled="!form"
|
||||||
|
>Connect</v-btn
|
||||||
|
>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-form>
|
</v-form>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|||||||
@@ -51,6 +51,15 @@ watch(
|
|||||||
<span class="message-time" v-if="!!msg.time">{{
|
<span class="message-time" v-if="!!msg.time">{{
|
||||||
formatTime(msg.time)
|
formatTime(msg.time)
|
||||||
}}</span>
|
}}</span>
|
||||||
|
<v-chip
|
||||||
|
class="ml-2"
|
||||||
|
v-bind="props"
|
||||||
|
label
|
||||||
|
color="purple-lighten-2"
|
||||||
|
v-if="msg.kind === 'notice'"
|
||||||
|
size="x-small"
|
||||||
|
><v-icon class="mr-2">mdi-eye</v-icon>Only visible to you
|
||||||
|
</v-chip>
|
||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
{{ msg.message }}
|
{{ msg.message }}
|
||||||
</v-list-item></template
|
</v-list-item></template
|
||||||
|
|||||||
88
app/frontend/src/components/Register.vue
Normal file
88
app/frontend/src/components/Register.vue
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { HookStatus, useIRCStore } from "@/stores/irc";
|
||||||
|
import { onBeforeMount, onBeforeUnmount } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
const router = useRouter();
|
||||||
|
const ircStore = useIRCStore();
|
||||||
|
const emit = defineEmits(["success"]);
|
||||||
|
|
||||||
|
const RegistrationSuccess = new RegExp(/Account created/);
|
||||||
|
function interceptNickServMessage(message: { nick: string; message: string }) {
|
||||||
|
if (message.nick !== "NickServ") {
|
||||||
|
return HookStatus.HOOK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
registering.value = false;
|
||||||
|
|
||||||
|
if (message.message.match(RegistrationSuccess)) {
|
||||||
|
emit("success");
|
||||||
|
}
|
||||||
|
|
||||||
|
return HookStatus.HOOK_EAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
ircStore.registerHook("message", interceptNickServMessage);
|
||||||
|
ircStore.registerHook("notice", interceptNickServMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
ircStore.unregisterHook("message", interceptNickServMessage);
|
||||||
|
ircStore.unregisterHook("notice", interceptNickServMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
const newAccount = ref({
|
||||||
|
email: "",
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = ref(false);
|
||||||
|
const registering = ref(false);
|
||||||
|
|
||||||
|
function register() {
|
||||||
|
if (!form.value) return;
|
||||||
|
|
||||||
|
const { password, email } = newAccount.value;
|
||||||
|
registering.value = true;
|
||||||
|
ircStore.client.say("NickServ", `REGISTER ${password} ${email}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
const show = ref(true);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<v-dialog v-model="show" max-width="400px" persistent>
|
||||||
|
<v-card title="Account Registration">
|
||||||
|
<v-form v-model="form" @submit.prevent="register">
|
||||||
|
<v-card-text>
|
||||||
|
<v-text-field
|
||||||
|
:rules="[(v) => !!v || 'Email required']"
|
||||||
|
v-model="newAccount.email"
|
||||||
|
label="Email"
|
||||||
|
role="email"
|
||||||
|
/>
|
||||||
|
<v-text-field
|
||||||
|
:rules="[(v) => !!v || 'Password required']"
|
||||||
|
v-model="newAccount.password"
|
||||||
|
label="Password"
|
||||||
|
role="password"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-btn
|
||||||
|
:disabled="!form"
|
||||||
|
type="submit"
|
||||||
|
:loading="registering"
|
||||||
|
text="Register"
|
||||||
|
color="success"
|
||||||
|
/>
|
||||||
|
<v-btn @click="cancel">Cancel</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-form>
|
||||||
|
</v-card></v-dialog
|
||||||
|
>
|
||||||
|
</template>
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import vuetify from "./vuetify";
|
import vuetify from "./vuetify";
|
||||||
import pinia from "@/stores";
|
import pinia from "@/stores";
|
||||||
|
import router from "./router.ts";
|
||||||
|
|
||||||
import type { App } from "vue";
|
import type { App } from "vue";
|
||||||
|
|
||||||
export function registerPlugins(app: App) {
|
export function registerPlugins(app: App) {
|
||||||
app.use(vuetify).use(pinia);
|
app.use(vuetify).use(router).use(pinia);
|
||||||
}
|
}
|
||||||
|
|||||||
37
app/frontend/src/plugins/router.ts
Normal file
37
app/frontend/src/plugins/router.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { createMemoryHistory, createRouter } from "vue-router";
|
||||||
|
import Chat from "@/components/Chat.vue";
|
||||||
|
import { useIRCStore } from "@/stores/irc";
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
name: "Chat",
|
||||||
|
component: Chat,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "register",
|
||||||
|
name: "Register",
|
||||||
|
component: () => import("@/components/Register.vue"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/login",
|
||||||
|
name: "Login",
|
||||||
|
component: () => import("@/components/Login.vue"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createMemoryHistory(),
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
|
||||||
|
router.beforeEach(async (to, from) => {
|
||||||
|
if (!useIRCStore().connected && to.name !== "Login") {
|
||||||
|
return { name: "Login" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
@@ -3,6 +3,7 @@ import { ref } from "vue";
|
|||||||
|
|
||||||
export const useAccountStore = defineStore("accountStore", () => {
|
export const useAccountStore = defineStore("accountStore", () => {
|
||||||
const authenticated = ref(false);
|
const authenticated = ref(false);
|
||||||
|
const showRegistration = ref(false);
|
||||||
const account = ref({
|
const account = ref({
|
||||||
nick: "",
|
nick: "",
|
||||||
account: "",
|
account: "",
|
||||||
@@ -21,5 +22,13 @@ export const useAccountStore = defineStore("accountStore", () => {
|
|||||||
account.value.nick = v;
|
account.value.nick = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { account, authError, authenticated, setAuthenticated, setNick };
|
return {
|
||||||
|
account,
|
||||||
|
authError,
|
||||||
|
authenticated,
|
||||||
|
showRegistration,
|
||||||
|
setAuthenticated,
|
||||||
|
setNick,
|
||||||
|
showRegistration,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,15 +1,50 @@
|
|||||||
import { defineStore, storeToRefs } from "pinia";
|
import { defineStore, storeToRefs } from "pinia";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
import { Client } from "irc-framework";
|
import { Client } from "irc-framework";
|
||||||
import { useBufferStore } from "./bufferStore";
|
import { useBufferStore } from "./bufferStore";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useAccountStore } from "./accountStore";
|
import { useAccountStore } from "./accountStore";
|
||||||
|
|
||||||
|
export type HookFunction = (event: any) => HookStatus;
|
||||||
|
|
||||||
|
export enum HookStatus {
|
||||||
|
HOOK_OK,
|
||||||
|
HOOK_EAT,
|
||||||
|
}
|
||||||
|
|
||||||
export const useIRCStore = defineStore("ircStore", () => {
|
export const useIRCStore = defineStore("ircStore", () => {
|
||||||
const bufferStore = useBufferStore();
|
const bufferStore = useBufferStore();
|
||||||
const accountStore = useAccountStore();
|
const accountStore = useAccountStore();
|
||||||
const connected = ref(false);
|
const connected = ref(false);
|
||||||
const { authError } = storeToRefs(accountStore);
|
const { authError } = storeToRefs(accountStore);
|
||||||
|
|
||||||
|
const hooks = {} as Record<string, HookFunction[]>;
|
||||||
|
|
||||||
|
function registerHook(event: string, f: HookFunction) {
|
||||||
|
if (hooks[event]) hooks[event].push(f);
|
||||||
|
else hooks[event] = [f];
|
||||||
|
}
|
||||||
|
|
||||||
|
function runHook(eventName: string, eventArgs: any): HookStatus {
|
||||||
|
if (!hooks[eventName]) return HookStatus.HOOK_OK;
|
||||||
|
let lastRetVal = HookStatus.HOOK_OK;
|
||||||
|
|
||||||
|
for (const hookFunction of hooks[eventName]) {
|
||||||
|
const retVal = hookFunction(eventArgs);
|
||||||
|
if (retVal === HookStatus.HOOK_EAT) return retVal;
|
||||||
|
lastRetVal = retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastRetVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterHook(eventName: string, f: HookFunction) {
|
||||||
|
if (!hooks[eventName]) return;
|
||||||
|
const idx = hooks[eventName].findIndex((item) => item === f);
|
||||||
|
if (idx === -1) return;
|
||||||
|
hooks[eventName].splice(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
const selfAvatar = ref("https://placekittens.com/128/128");
|
const selfAvatar = ref("https://placekittens.com/128/128");
|
||||||
const bio = ref();
|
const bio = ref();
|
||||||
|
|
||||||
@@ -85,7 +120,6 @@ export const useIRCStore = defineStore("ircStore", () => {
|
|||||||
nick: accountStore.account.nick,
|
nick: accountStore.account.nick,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(connectParams);
|
|
||||||
client.connect(connectParams);
|
client.connect(connectParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,11 +127,12 @@ export const useIRCStore = defineStore("ircStore", () => {
|
|||||||
if (!bufferStore.activeBuffer) {
|
if (!bufferStore.activeBuffer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (bufferStore.activeBuffer.channel)
|
||||||
bufferStore.activeBuffer.channel.say(message);
|
bufferStore.activeBuffer.channel.say(message);
|
||||||
|
else client.say(bufferStore.activeBuffer.name, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMe(target: string) {
|
function isMe(target: string) {
|
||||||
console.log(client.user.nick);
|
|
||||||
return target === client.user.nick;
|
return target === client.user.nick;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,8 +164,10 @@ export const useIRCStore = defineStore("ircStore", () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
client.on("registered", function () {
|
client.on("registered", function () {
|
||||||
connected.value = true;
|
connected.value = true;
|
||||||
|
router.push({ name: "Chat" });
|
||||||
client.list();
|
client.list();
|
||||||
client.raw("METADATA * SUB avatar");
|
client.raw("METADATA * SUB avatar");
|
||||||
client.raw("METADATA * SUB bio");
|
client.raw("METADATA * SUB bio");
|
||||||
@@ -207,14 +244,22 @@ export const useIRCStore = defineStore("ircStore", () => {
|
|||||||
|
|
||||||
client.on("message", function (message: { nick: string; target: string }) {
|
client.on("message", function (message: { nick: string; target: string }) {
|
||||||
let buffer;
|
let buffer;
|
||||||
|
|
||||||
|
const retVal = runHook("message", message);
|
||||||
|
if (retVal === HookStatus.HOOK_EAT) return;
|
||||||
|
|
||||||
if (message.nick === "HistServ") return;
|
if (message.nick === "HistServ") return;
|
||||||
if (isMe(message.target)) {
|
if (isMe(message.target)) {
|
||||||
buffer = bufferStore.getBuffer(message.nick);
|
buffer = bufferStore.getBuffer(message.nick);
|
||||||
} else {
|
} else {
|
||||||
buffer = bufferStore.getBuffer(message.target);
|
buffer = bufferStore.getBuffer(message.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return;
|
buffer = bufferStore.addBuffer(message.nick, {
|
||||||
|
name: message.nick,
|
||||||
|
channel: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.messages.push(message);
|
buffer.messages.push(message);
|
||||||
@@ -227,6 +272,14 @@ export const useIRCStore = defineStore("ircStore", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
client.on("notice", function (message) {
|
||||||
|
const retVal = runHook("notice", message);
|
||||||
|
if (retVal === HookStatus.HOOK_EAT) return;
|
||||||
|
if (bufferStore.activeBuffer) {
|
||||||
|
bufferStore.activeBuffer.messages.push({ ...message, kind: "notice" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
client.on("join", ({ nick, channel }: { nick: string; channel: string }) => {
|
client.on("join", ({ nick, channel }: { nick: string; channel: string }) => {
|
||||||
if (isMe(nick)) {
|
if (isMe(nick)) {
|
||||||
bufferStore.addBuffer(channel, {
|
bufferStore.addBuffer(channel, {
|
||||||
@@ -294,5 +347,7 @@ export const useIRCStore = defineStore("ircStore", () => {
|
|||||||
setBio,
|
setBio,
|
||||||
bio,
|
bio,
|
||||||
connected,
|
connected,
|
||||||
|
registerHook,
|
||||||
|
unregisterHook,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
299
app/package-lock.json
generated
299
app/package-lock.json
generated
@@ -1,6 +1,301 @@
|
|||||||
{
|
{
|
||||||
"name": "IrChad",
|
"name": "app",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {}
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"vue-router": "^4.6.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/helper-string-parser": {
|
||||||
|
"version": "7.27.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
||||||
|
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
|
"version": "7.28.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
||||||
|
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/parser": {
|
||||||
|
"version": "7.28.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz",
|
||||||
|
"integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/types": "^7.28.6"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"parser": "bin/babel-parser.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/types": {
|
||||||
|
"version": "7.28.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz",
|
||||||
|
"integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/helper-string-parser": "^7.27.1",
|
||||||
|
"@babel/helper-validator-identifier": "^7.28.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
|
"version": "1.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||||
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@vue/compiler-core": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/parser": "^7.28.5",
|
||||||
|
"@vue/shared": "3.5.26",
|
||||||
|
"entities": "^7.0.0",
|
||||||
|
"estree-walker": "^2.0.2",
|
||||||
|
"source-map-js": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vue/compiler-dom": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/compiler-core": "3.5.26",
|
||||||
|
"@vue/shared": "3.5.26"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vue/compiler-sfc": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/parser": "^7.28.5",
|
||||||
|
"@vue/compiler-core": "3.5.26",
|
||||||
|
"@vue/compiler-dom": "3.5.26",
|
||||||
|
"@vue/compiler-ssr": "3.5.26",
|
||||||
|
"@vue/shared": "3.5.26",
|
||||||
|
"estree-walker": "^2.0.2",
|
||||||
|
"magic-string": "^0.30.21",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"source-map-js": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vue/compiler-ssr": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/compiler-dom": "3.5.26",
|
||||||
|
"@vue/shared": "3.5.26"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vue/devtools-api": {
|
||||||
|
"version": "6.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
|
||||||
|
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@vue/reactivity": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/shared": "3.5.26"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vue/runtime-core": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/reactivity": "3.5.26",
|
||||||
|
"@vue/shared": "3.5.26"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vue/runtime-dom": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/reactivity": "3.5.26",
|
||||||
|
"@vue/runtime-core": "3.5.26",
|
||||||
|
"@vue/shared": "3.5.26",
|
||||||
|
"csstype": "^3.2.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vue/server-renderer": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/compiler-ssr": "3.5.26",
|
||||||
|
"@vue/shared": "3.5.26"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "3.5.26"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vue/shared": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/csstype": {
|
||||||
|
"version": "3.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||||
|
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/entities": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/estree-walker": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/magic-string": {
|
||||||
|
"version": "0.30.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||||
|
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||||
|
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.5.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||||
|
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.11",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"source-map-js": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vue": {
|
||||||
|
"version": "3.5.26",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.26.tgz",
|
||||||
|
"integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/compiler-dom": "3.5.26",
|
||||||
|
"@vue/compiler-sfc": "3.5.26",
|
||||||
|
"@vue/runtime-dom": "3.5.26",
|
||||||
|
"@vue/server-renderer": "3.5.26",
|
||||||
|
"@vue/shared": "3.5.26"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vue-router": {
|
||||||
|
"version": "4.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
|
||||||
|
"integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/devtools-api": "^6.6.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/posva"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.5.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
app/package.json
Normal file
5
app/package.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"vue-router": "^4.6.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user