megacommit
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import van from "./van.js";
|
||||
const { button, div, span, h1, img, p, input } = van.tags;
|
||||
|
||||
import markdownit from "https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/+esm";
|
||||
import hljs from "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
||||
|
||||
// Markdown configuration (matching the HTML)
|
||||
const md = markdownit({
|
||||
html: true,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(str, { language: lang }).value;
|
||||
} catch (__) {}
|
||||
}
|
||||
|
||||
return ""; // use external default escaping
|
||||
},
|
||||
});
|
||||
|
||||
export const messages = van.state([]);
|
||||
export const users = van.state({});
|
||||
|
||||
// Helper function to render Markdown
|
||||
function renderMarkdown(text) {
|
||||
return md.render(text);
|
||||
}
|
||||
|
||||
// Component for a single message
|
||||
function Message(message) {
|
||||
const userName = users[message.user_id] || "Unknown User"; // Get username from state or default
|
||||
|
||||
const content = div({ class: "message-text" });
|
||||
content.innerHTML = renderMarkdown(message.text);
|
||||
|
||||
return div(
|
||||
{ class: "message" },
|
||||
img({ class: "user-avatar", src: `cdn/profile/${message.user_id}` }),
|
||||
div(
|
||||
{ class: "message-content" },
|
||||
div(
|
||||
{ class: "message-header" },
|
||||
span({ class: "username" }, userName),
|
||||
span(
|
||||
{ class: "timestamp" },
|
||||
new Date(message.timestamp).toLocaleTimeString("en-GB"),
|
||||
),
|
||||
),
|
||||
content, // Render Markdown here
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Component for the entire chat interface
|
||||
function ChatApp() {
|
||||
return div(
|
||||
{ class: "chat-container" },
|
||||
div(
|
||||
{ class: "chat-header" },
|
||||
div(
|
||||
{ class: "chat-title" },
|
||||
img({ class: "user-avatar", src: "cdn/profile/0" }),
|
||||
h1(null, "Wish.com Discord frfr"),
|
||||
),
|
||||
),
|
||||
|
||||
van.derive(() => {
|
||||
console.log("Deriving messages");
|
||||
const container = div({ class: "messages-container" });
|
||||
|
||||
for (const message of messages.val) {
|
||||
van.add(container, Message(message));
|
||||
}
|
||||
return container;
|
||||
}),
|
||||
|
||||
div(
|
||||
{ class: "input-container" },
|
||||
div(
|
||||
{ class: "input-wrapper" },
|
||||
input({ type: "text", placeholder: "Start Typing..." }),
|
||||
button(
|
||||
{ class: "send-button", onclick: () => sendMessage() },
|
||||
img({ src: "cdn/icons/send.svg" }),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async function sendMessage() {
|
||||
const messageInput = document.querySelector(".input-wrapper input");
|
||||
const message = messageInput.value.trim();
|
||||
|
||||
if (message) {
|
||||
await fetch("/api/chat/", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
user_id: user_id,
|
||||
text: message,
|
||||
timestamp: new Date().getTime(),
|
||||
}),
|
||||
});
|
||||
|
||||
messageInput.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Function to fetch user data (replace with your actual API endpoint)
|
||||
async function fetchUsers() {
|
||||
try {
|
||||
const userIds = await fetch("/api/users/").then((r) => r.json());
|
||||
|
||||
const userPromises = userIds.map((userId) =>
|
||||
fetch(`/api/users/${userId}`)
|
||||
.then((r) => r.text())
|
||||
.then((username) => ({ userId, username })),
|
||||
);
|
||||
|
||||
const userData = await Promise.all(userPromises);
|
||||
|
||||
userData.forEach(({ userId, username }) => {
|
||||
users.val[userId] = username;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching users:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to handle incoming messages from SSE
|
||||
function handleSSEMessage(event) {
|
||||
let message = JSON.parse(event.data);
|
||||
messages.val = [...messages.val, message];
|
||||
}
|
||||
|
||||
// Initialize the application
|
||||
async function init() {
|
||||
await fetchUsers();
|
||||
|
||||
const eventSource = new EventSource("/api/events"); // Replace with your SSE endpoint
|
||||
|
||||
eventSource.onopen = () => console.log("SSE connection opened");
|
||||
eventSource.onmessage = handleSSEMessage;
|
||||
eventSource.onerror = (error) => {
|
||||
console.error("EventSource error:", error);
|
||||
// Attempt to reconnect after a delay
|
||||
setTimeout(() => eventSource.open(), 5000);
|
||||
};
|
||||
|
||||
van.add(document.body, ChatApp());
|
||||
}
|
||||
|
||||
init();
|
||||
Vendored
+1407
File diff suppressed because one or more lines are too long
@@ -0,0 +1,125 @@
|
||||
let e,
|
||||
t,
|
||||
r,
|
||||
o,
|
||||
l,
|
||||
s,
|
||||
n = Object.getPrototypeOf,
|
||||
i = { isConnected: 1 },
|
||||
f = {},
|
||||
h = n(i),
|
||||
u = n(n),
|
||||
a = (e, t, r, o) =>
|
||||
(e ?? (o ? setTimeout(r, o) : queueMicrotask(r), new Set())).add(t),
|
||||
d = (e, t, o) => {
|
||||
let l = r;
|
||||
r = t;
|
||||
try {
|
||||
return e(o);
|
||||
} catch (e) {
|
||||
return (console.error(e), o);
|
||||
} finally {
|
||||
r = l;
|
||||
}
|
||||
},
|
||||
w = (e) => e.filter((e) => e.t?.isConnected),
|
||||
c = (e) =>
|
||||
(l = a(
|
||||
l,
|
||||
e,
|
||||
() => {
|
||||
for (let e of l) ((e.o = w(e.o)), (e.l = w(e.l)));
|
||||
l = s;
|
||||
},
|
||||
1e3,
|
||||
)),
|
||||
_ = {
|
||||
get val() {
|
||||
return (r?.i?.add(this), this.rawVal);
|
||||
},
|
||||
get oldVal() {
|
||||
return (r?.i?.add(this), this.h);
|
||||
},
|
||||
set val(o) {
|
||||
(r?.u?.add(this),
|
||||
o !== this.rawVal &&
|
||||
((this.rawVal = o),
|
||||
this.o.length + this.l.length
|
||||
? (t?.add(this), (e = a(e, this, v)))
|
||||
: (this.h = o)));
|
||||
},
|
||||
},
|
||||
S = (e) => ({ __proto__: _, rawVal: e, h: e, o: [], l: [] }),
|
||||
g = (e, t) => {
|
||||
let r = { i: new Set(), u: new Set() },
|
||||
l = { f: e },
|
||||
s = o;
|
||||
o = [];
|
||||
let n = d(e, r, t);
|
||||
n = (n ?? document).nodeType ? n : new Text(n);
|
||||
for (let e of r.i) r.u.has(e) || (c(e), e.o.push(l));
|
||||
for (let e of o) e.t = n;
|
||||
return ((o = s), (l.t = n));
|
||||
},
|
||||
y = (e, t = S(), r) => {
|
||||
let l = { i: new Set(), u: new Set() },
|
||||
s = { f: e, s: t };
|
||||
((s.t = r ?? o?.push(s) ?? i), (t.val = d(e, l, t.rawVal)));
|
||||
for (let e of l.i) l.u.has(e) || (c(e), e.l.push(s));
|
||||
return t;
|
||||
},
|
||||
b = (e, ...t) => {
|
||||
for (let r of t.flat(1 / 0)) {
|
||||
let t = n(r ?? 0),
|
||||
o = t === _ ? g(() => r.val) : t === u ? g(r) : r;
|
||||
o != s && e.append(o);
|
||||
}
|
||||
return e;
|
||||
},
|
||||
m = (e, t, ...r) => {
|
||||
let [{ is: o, ...l }, ...i] = n(r[0] ?? 0) === h ? r : [{}, ...r],
|
||||
a = e
|
||||
? document.createElementNS(e, t, { is: o })
|
||||
: document.createElement(t, { is: o });
|
||||
for (let [e, r] of Object.entries(l)) {
|
||||
let o = (t) =>
|
||||
t ? (Object.getOwnPropertyDescriptor(t, e) ?? o(n(t))) : s,
|
||||
l = t + "," + e,
|
||||
i = (f[l] ??= o(n(a))?.set ?? 0),
|
||||
h = e.startsWith("on")
|
||||
? (t, r) => {
|
||||
let o = e.slice(2);
|
||||
(a.removeEventListener(o, r), a.addEventListener(o, t));
|
||||
}
|
||||
: i
|
||||
? i.bind(a)
|
||||
: a.setAttribute.bind(a, e),
|
||||
d = n(r ?? 0);
|
||||
(e.startsWith("on") || (d === u && ((r = y(r)), (d = _))),
|
||||
d === _ ? g(() => (h(r.val, r.h), a)) : h(r));
|
||||
}
|
||||
return b(a, i);
|
||||
},
|
||||
x = (e) => ({ get: (t, r) => m.bind(s, e, r) }),
|
||||
j = (e, t) => (t ? t !== e && e.replaceWith(t) : e.remove()),
|
||||
v = () => {
|
||||
let r = 0,
|
||||
o = [...e].filter((e) => e.rawVal !== e.h);
|
||||
do {
|
||||
t = new Set();
|
||||
for (let e of new Set(o.flatMap((e) => (e.l = w(e.l)))))
|
||||
(y(e.f, e.s, e.t), (e.t = s));
|
||||
} while (++r < 100 && (o = [...t]).length);
|
||||
let l = [...e].filter((e) => e.rawVal !== e.h);
|
||||
e = s;
|
||||
for (let e of new Set(l.flatMap((e) => (e.o = w(e.o)))))
|
||||
(j(e.t, g(e.f, e.t)), (e.t = s));
|
||||
for (let e of l) e.h = e.rawVal;
|
||||
};
|
||||
export default {
|
||||
tags: new Proxy((e) => new Proxy(m, x(e)), x()),
|
||||
hydrate: (e, t) => j(e, g(t, e)),
|
||||
add: b,
|
||||
state: S,
|
||||
derive: y,
|
||||
};
|
||||
Reference in New Issue
Block a user