Add the CSS to amek this work, log better in the app
This commit is contained in:
parent
8b55e01bfa
commit
add5c2f654
@ -50,18 +50,27 @@ function sendMessage(e) {
|
|||||||
const MessageInput = {
|
const MessageInput = {
|
||||||
view: function () {
|
view: function () {
|
||||||
return m("div.chat-input", [
|
return m("div.chat-input", [
|
||||||
m("form", { method: "post", onsubmit: sendMessage }, [
|
m("form", { method: "post", onsubmit: this.handleSubmit }, [
|
||||||
m("input", { name: "chatter", placeholder: "Name" }),
|
m("input", { name: "chatter", placeholder: "Name" }),
|
||||||
m("input", { name: "message", placeholder: "Message", id: "message", required: true }),
|
m("input", { name: "message", placeholder: "Message", id: "message", required: true }),
|
||||||
m("input", { type: "submit", value: "Send" })
|
m("input", { type: "submit", value: "Send" })
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
},
|
||||||
|
nameHidden: false,
|
||||||
|
handleSubmit: function (e) {
|
||||||
|
sendMessage(e);
|
||||||
|
if (!this.nameHidden) {
|
||||||
|
const chatterInput = document.querySelector('input[name="chatter"]')
|
||||||
|
chatterInput.setAttribute('style', 'display: none');
|
||||||
|
this.nameHidden = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Chat = {
|
const Chat = {
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
return m("div", [
|
return m("div", { class: 'container' }, [
|
||||||
m(MessageBox),
|
m(MessageBox),
|
||||||
m(MessageInput)
|
m(MessageInput)
|
||||||
])
|
])
|
||||||
|
@ -14,16 +14,15 @@ const { upgradeWebSocket, websocket } = createBunWebSocket<ServerWebSocket>();
|
|||||||
app.get("/chat-service", upgradeWebSocket((c) => {
|
app.get("/chat-service", upgradeWebSocket((c) => {
|
||||||
return {
|
return {
|
||||||
onOpen(event, ws) {
|
onOpen(event, ws) {
|
||||||
console.log(`Connection established from ${ws.raw.remoteAddress}`);
|
console.log(JSON.stringify({ message: `Connection established`, remoteHost: ws.raw.remoteAddress }));
|
||||||
|
|
||||||
chatRoom.addListener('message-added', async function (e) {
|
chatRoom.addListener('message-added', function (e) {
|
||||||
const message = JSON.stringify({
|
const message = JSON.stringify({
|
||||||
message: e.message.message,
|
message: e.message.message,
|
||||||
chatter: e.message.chatter,
|
chatter: e.message.chatter,
|
||||||
timestamp: e.message.timestamp
|
timestamp: e.message.timestamp
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(message);
|
|
||||||
ws.send(message);
|
ws.send(message);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -33,12 +32,13 @@ app.get("/chat-service", upgradeWebSocket((c) => {
|
|||||||
message.timestamp = Date.now() as string;
|
message.timestamp = Date.now() as string;
|
||||||
|
|
||||||
chatRoom.addMessage(message);
|
chatRoom.addMessage(message);
|
||||||
|
console.log(JSON.stringify(message));
|
||||||
},
|
},
|
||||||
onClose() {
|
onClose() {
|
||||||
console.log("Connection closed.");
|
console.log(JSON.stringify({ message: `Connection closed.` }));
|
||||||
},
|
},
|
||||||
onError(event, ws) {
|
onError(event, ws) {
|
||||||
console.error(event);
|
console.error(JSON.stringify({ event }));
|
||||||
ws.close();
|
ws.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,4 +55,4 @@ Bun.serve({
|
|||||||
websocket
|
websocket
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Chat is running on ${process.env.APP_PORT}`);
|
console.log(JSON.stringify({ message: `Chat is running`, port: process.env.APP_PORT}));
|
||||||
|
@ -9,12 +9,19 @@ div {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
.messages {
|
.messages {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
height: auto;
|
flex-grow: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.messages .message {
|
.messages .message {
|
||||||
@ -33,14 +40,12 @@ div {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chat-input {
|
.chat-input {
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
height: auto;
|
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
background-color: #f4efe6;
|
background-color: #f4efe6;
|
||||||
|
align-self: flex-end;
|
||||||
}
|
}
|
||||||
.chat-input > form {
|
.chat-input > form {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -51,6 +56,8 @@ div {
|
|||||||
.chat-input > form > submit {
|
.chat-input > form > submit {
|
||||||
padding: 1em 1.25em;
|
padding: 1em 1.25em;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-famil: monospace !important;
|
||||||
}
|
}
|
||||||
.chat-input > form > submit {
|
.chat-input > form > submit {
|
||||||
background-color: #020a03;
|
background-color: #020a03;
|
||||||
@ -58,7 +65,6 @@ div {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: #fffbf6;
|
color: #fffbf6;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-family: monospace !important;
|
|
||||||
padding: 0.75em 1em;
|
padding: 0.75em 1em;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
@ -67,47 +73,48 @@ div {
|
|||||||
border: 1px solid #020a03;
|
border: 1px solid #020a03;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: #0c0b09;
|
color: #0c0b09;
|
||||||
font-family: monospace;
|
|
||||||
}
|
}
|
||||||
.chat-input > form > input[name="message"] {
|
.chat-input > form > input[name="message"] {
|
||||||
width: 75%;
|
width: 75%;
|
||||||
border: 1px solid #020a03;
|
border: 1px solid #020a03;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: #0c0b09;
|
color: #0c0b09;
|
||||||
font-family: monospace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
.chat-input {
|
.chat-input {
|
||||||
padding: 2.5em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-input > form {
|
.chat-input > form {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex-direction: column;
|
}
|
||||||
|
|
||||||
|
.chat-input > form > input,
|
||||||
|
.chat-input > form > submit {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0.25em;
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 0.75em 1em;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-input > form > input[name="chatter"] {
|
.chat-input > form > input[name="chatter"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 3.5em;
|
order: 1;
|
||||||
margin-bottom: 0.5em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-input > form > input[name="message"] {
|
.chat-input > form > input[name="message"] {
|
||||||
width: 100%;
|
width: 60%;
|
||||||
font-size: 3.5em;
|
order: 2;
|
||||||
margin-bottom: 0.5em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-input > form > input[type=submit] {
|
||||||
.chat-input > form > input, .chat-input > form > submit {
|
width: 34%;
|
||||||
padding: 0.75em 1em;
|
order: 3;
|
||||||
border-radius: 0.25em;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 3.5em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>A Dumb Chat Application</title>
|
<title>A Dumb Chat Application</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" type="text/css" href="/css/main.css" />
|
<link rel="stylesheet" type="text/css" href="/css/main.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -79,11 +79,6 @@ var require_hasOwn = __commonJS((exports, module) => {
|
|||||||
|
|
||||||
// node_modules/mithril/render/hyperscript.js
|
// node_modules/mithril/render/hyperscript.js
|
||||||
var require_hyperscript = __commonJS((exports, module) => {
|
var require_hyperscript = __commonJS((exports, module) => {
|
||||||
var Vnode = require_vnode();
|
|
||||||
var hyperscriptVnode = require_hyperscriptVnode();
|
|
||||||
var hasOwn = require_hasOwn();
|
|
||||||
var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g;
|
|
||||||
var selectorCache = {};
|
|
||||||
function isEmpty(object) {
|
function isEmpty(object) {
|
||||||
for (var key in object)
|
for (var key in object)
|
||||||
if (hasOwn.call(object, key))
|
if (hasOwn.call(object, key))
|
||||||
@ -152,6 +147,11 @@ var require_hyperscript = __commonJS((exports, module) => {
|
|||||||
vnode.tag = selector;
|
vnode.tag = selector;
|
||||||
return vnode;
|
return vnode;
|
||||||
}
|
}
|
||||||
|
var Vnode = require_vnode();
|
||||||
|
var hyperscriptVnode = require_hyperscriptVnode();
|
||||||
|
var hasOwn = require_hasOwn();
|
||||||
|
var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g;
|
||||||
|
var selectorCache = {};
|
||||||
module.exports = hyperscript;
|
module.exports = hyperscript;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -187,7 +187,6 @@ var require_hyperscript2 = __commonJS((exports, module) => {
|
|||||||
|
|
||||||
// node_modules/mithril/render/domFor.js
|
// node_modules/mithril/render/domFor.js
|
||||||
var require_domFor = __commonJS((exports, module) => {
|
var require_domFor = __commonJS((exports, module) => {
|
||||||
var delayedRemoval = new WeakMap;
|
|
||||||
function* domFor({ dom, domSize }, { generation } = {}) {
|
function* domFor({ dom, domSize }, { generation } = {}) {
|
||||||
if (dom != null)
|
if (dom != null)
|
||||||
do {
|
do {
|
||||||
@ -199,6 +198,7 @@ var require_domFor = __commonJS((exports, module) => {
|
|||||||
dom = nextSibling;
|
dom = nextSibling;
|
||||||
} while (domSize);
|
} while (domSize);
|
||||||
}
|
}
|
||||||
|
var delayedRemoval = new WeakMap;
|
||||||
module.exports = {
|
module.exports = {
|
||||||
delayedRemoval,
|
delayedRemoval,
|
||||||
domFor
|
domFor
|
||||||
@ -1480,6 +1480,13 @@ var require_censor = __commonJS((exports, module) => {
|
|||||||
|
|
||||||
// node_modules/mithril/api/router.js
|
// node_modules/mithril/api/router.js
|
||||||
var require_router = __commonJS((exports, module) => {
|
var require_router = __commonJS((exports, module) => {
|
||||||
|
function decodeURIComponentSave(component) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(component);
|
||||||
|
} catch (e) {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
var Vnode = require_vnode();
|
var Vnode = require_vnode();
|
||||||
var m = require_hyperscript();
|
var m = require_hyperscript();
|
||||||
var buildPathname = require_build2();
|
var buildPathname = require_build2();
|
||||||
@ -1488,13 +1495,6 @@ var require_router = __commonJS((exports, module) => {
|
|||||||
var assign = require_assign();
|
var assign = require_assign();
|
||||||
var censor = require_censor();
|
var censor = require_censor();
|
||||||
var sentinel = {};
|
var sentinel = {};
|
||||||
function decodeURIComponentSave(component) {
|
|
||||||
try {
|
|
||||||
return decodeURIComponent(component);
|
|
||||||
} catch (e) {
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module.exports = function($window, mountRedraw) {
|
module.exports = function($window, mountRedraw) {
|
||||||
var callAsync = $window == null ? null : typeof $window.setImmediate === "function" ? $window.setImmediate : $window.setTimeout;
|
var callAsync = $window == null ? null : typeof $window.setImmediate === "function" ? $window.setImmediate : $window.setTimeout;
|
||||||
var p = Promise.resolve();
|
var p = Promise.resolve();
|
||||||
@ -1721,34 +1721,18 @@ var import_mithril = __toESM(require_mithril(), 1);
|
|||||||
|
|
||||||
// frontend/websocket.js
|
// frontend/websocket.js
|
||||||
function createWebSocket() {
|
function createWebSocket() {
|
||||||
let appUrl = "chat.freedoom.party";
|
let appUrl = "localhost:3000";
|
||||||
appUrl = `//${appUrl}/chat-service`;
|
appUrl = `//${appUrl}/chat-service`;
|
||||||
return new WebSocket(appUrl);
|
return new WebSocket(appUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// frontend/index.js
|
// frontend/index.js
|
||||||
var messages = [];
|
|
||||||
var socket = createWebSocket();
|
|
||||||
socket.onmessage = function(event) {
|
|
||||||
if (event.type === "message") {
|
|
||||||
const message = JSON.parse(event.data);
|
|
||||||
messages.push(message);
|
|
||||||
import_mithril.default.redraw();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function newMessageText(name, message) {
|
function newMessageText(name, message) {
|
||||||
return [
|
return [
|
||||||
import_mithril.default("span.chatter", name + ": "),
|
import_mithril.default("span.chatter", name + ": "),
|
||||||
import_mithril.default("span.chatter-message", message)
|
import_mithril.default("span.chatter-message", message)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
var MessageBox = {
|
|
||||||
view: function() {
|
|
||||||
return import_mithril.default(".messages", { id: "message-box" }, messages.reverse().map(function(message) {
|
|
||||||
return import_mithril.default(".message", newMessageText(message.chatter, message.message));
|
|
||||||
}), import_mithril.default("#anchor"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function clearMessageInputBox() {
|
function clearMessageInputBox() {
|
||||||
const messageBox = document.getElementById("message");
|
const messageBox = document.getElementById("message");
|
||||||
messageBox.value = "";
|
messageBox.value = "";
|
||||||
@ -1763,20 +1747,45 @@ function sendMessage(e) {
|
|||||||
socket.send(JSON.stringify(message));
|
socket.send(JSON.stringify(message));
|
||||||
clearMessageInputBox();
|
clearMessageInputBox();
|
||||||
}
|
}
|
||||||
|
var messages = [];
|
||||||
|
var socket = createWebSocket();
|
||||||
|
socket.onmessage = function(event) {
|
||||||
|
if (event.type === "message") {
|
||||||
|
const message = JSON.parse(event.data);
|
||||||
|
messages.push(message);
|
||||||
|
import_mithril.default.redraw();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var MessageBox = {
|
||||||
|
view: function() {
|
||||||
|
return import_mithril.default(".messages", { id: "message-box" }, messages.reverse().map(function(message) {
|
||||||
|
return import_mithril.default(".message", newMessageText(message.chatter, message.message));
|
||||||
|
}), import_mithril.default("#anchor"));
|
||||||
|
}
|
||||||
|
};
|
||||||
var MessageInput = {
|
var MessageInput = {
|
||||||
view: function() {
|
view: function() {
|
||||||
return import_mithril.default("div.chat-input", [
|
return import_mithril.default("div.chat-input", [
|
||||||
import_mithril.default("form", { method: "post", onsubmit: sendMessage }, [
|
import_mithril.default("form", { method: "post", onsubmit: this.handleSubmit }, [
|
||||||
import_mithril.default("input", { name: "chatter", placeholder: "Name" }),
|
import_mithril.default("input", { name: "chatter", placeholder: "Name" }),
|
||||||
import_mithril.default("input", { name: "message", placeholder: "Message", id: "message", required: true }),
|
import_mithril.default("input", { name: "message", placeholder: "Message", id: "message", required: true }),
|
||||||
import_mithril.default("input", { type: "submit", value: "Send" })
|
import_mithril.default("input", { type: "submit", value: "Send" })
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
},
|
||||||
|
nameHidden: false,
|
||||||
|
handleSubmit: function(e) {
|
||||||
|
sendMessage(e);
|
||||||
|
if (!this.nameHidden) {
|
||||||
|
const chatterInput = document.querySelector('input[name="chatter"]');
|
||||||
|
chatterInput.setAttribute("style", "display: none");
|
||||||
|
this.nameHidden = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var Chat = {
|
var Chat = {
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
return import_mithril.default("div", [
|
return import_mithril.default("div", { class: "container" }, [
|
||||||
import_mithril.default(MessageBox),
|
import_mithril.default(MessageBox),
|
||||||
import_mithril.default(MessageInput)
|
import_mithril.default(MessageInput)
|
||||||
]);
|
]);
|
||||||
|
Loading…
Reference in New Issue
Block a user