Start thinking about how to actually use Mithril to build a frontend for this app.
This commit is contained in:
parent
15c405da6e
commit
03c51e7dbe
@ -1,4 +1,28 @@
|
|||||||
Bun.build({
|
async function main() {
|
||||||
entrypoints: [ "./src/components/index.js" ],
|
const results = await Bun.build({
|
||||||
outdir: "./static/js/",
|
entrypoints: [ "./frontend/index.js" ],
|
||||||
});
|
outdir: "./static/js/",
|
||||||
|
verbose: true
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (!results.success) {
|
||||||
|
for (const message of results.logs) {
|
||||||
|
console.error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
||||||
|
.then(() => {
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
Binary file not shown.
@ -2,11 +2,13 @@ import m from "mithril";
|
|||||||
import { MessageBox } from "./MessageBox";
|
import { MessageBox } from "./MessageBox";
|
||||||
import { LoginForm } from "./Login";
|
import { LoginForm } from "./Login";
|
||||||
|
|
||||||
export const ChatApp = {
|
export function createChatApp({ ws, session }) {
|
||||||
view: function () {
|
return {
|
||||||
return m("div", { class: "container" }, [
|
view: function () {
|
||||||
m("h1", "A Stupid Chat Application"),
|
return m("div", { class: "container" }, [
|
||||||
m(LoginForm)
|
m("h1", "A Stupid Chat Application"),
|
||||||
]);
|
m(LoginForm)
|
||||||
}
|
]);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1,11 +1,37 @@
|
|||||||
import m from "mithril";
|
import m from "mithril";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
|
||||||
export const LoginForm = {
|
export function LoginForm() {
|
||||||
view: function() {
|
let loggedIn = false;
|
||||||
return m("form", { action: "/login" }, [
|
|
||||||
m("label", { for: "username" }, "Username"),
|
async function login(e) {
|
||||||
m("input", { type: "text", name: "username" }),
|
e.preventDefault();
|
||||||
m("input", { type: "submit", value: "Login" })
|
|
||||||
]);
|
const formData = new FormData(e.target);
|
||||||
|
|
||||||
|
const res = await m.request({
|
||||||
|
method: "POST",
|
||||||
|
url: "/login",
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.success) {
|
||||||
|
Cookies.set('logged-in', true);
|
||||||
|
} else {
|
||||||
|
Cookies.remove('logged-in');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
return {
|
||||||
|
oninit: function() {
|
||||||
|
loggedIn = !!Cookies.get('logged-in');
|
||||||
|
},
|
||||||
|
view: function() {
|
||||||
|
return m("form", { action: "/login", method: "post", onsubmit: login }, [
|
||||||
|
m("label", { for: "username" }, "Username"),
|
||||||
|
m("input", { type: "text", name: "username" }),
|
||||||
|
m("input", { type: "submit", value: "Login" })
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import m from "mithril";
|
import m from "mithril";
|
||||||
import { ChatApp } from "./components/ChatApp";
|
import { createChatApp } from "./components/ChatApp";
|
||||||
|
import { createWebSocket } from "./websocket";
|
||||||
const localState = {
|
import { Sessions } from "./session";
|
||||||
messages: []
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// open the WS to the server
|
||||||
|
const ws = createWebSocket();
|
||||||
|
const session = new Sessions();
|
||||||
|
const ChatApp = createChatApp({ ws, session });
|
||||||
m.mount(document.getElementById("app"), ChatApp);
|
m.mount(document.getElementById("app"), ChatApp);
|
||||||
|
31
chat-app/frontend/session.js
Normal file
31
chat-app/frontend/session.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export class Sessions extends EventManager {
|
||||||
|
constructor() {
|
||||||
|
this.users = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
userExists(user) {
|
||||||
|
return !!this.findUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
findUser(user) {
|
||||||
|
return this.users.find(u => u.username === user.username);
|
||||||
|
}
|
||||||
|
|
||||||
|
addUser(user) {
|
||||||
|
if (!this.userExists(user)) {
|
||||||
|
this.users.push(user);
|
||||||
|
this.emit('user-logged-in', user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearUser(user) {
|
||||||
|
if (this.userExists(user)) {
|
||||||
|
const index = this.users.indexOf(user);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
this.users.splice(index - 1, 1);
|
||||||
|
this.emit('user-removed', user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
chat-app/frontend/websocket.js
Normal file
3
chat-app/frontend/websocket.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function createWebSocket() {
|
||||||
|
return new WebSocket("ws://localhost:3000/chat-service");
|
||||||
|
}
|
8
chat-app/justfile
Normal file
8
chat-app/justfile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
build:
|
||||||
|
bun build.ts
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -r static/js/*
|
||||||
|
|
||||||
|
test:
|
||||||
|
bun test
|
@ -2,11 +2,13 @@
|
|||||||
"name": "chat-app",
|
"name": "chat-app",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun run --hot src/index.ts",
|
"dev": "bun run --hot src/index.ts",
|
||||||
"build": "bun src/build.ts"
|
"build": "rm -r static/js && bun build.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mithril": "^2.2.7",
|
"@types/mithril": "^2.2.7",
|
||||||
"hono": "^4.6.3",
|
"hono": "^4.6.3",
|
||||||
|
"js-cookie": "^3.0.5",
|
||||||
|
"js-guid": "^1.0.2",
|
||||||
"mithril": "^2.2.5"
|
"mithril": "^2.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -13,8 +13,16 @@ const users: string[] = [];
|
|||||||
|
|
||||||
// Set up the chat socket
|
// Set up the chat socket
|
||||||
const { upgradeWebSocket, websocket } = createBunWebSocket<ServerWebSocket>();
|
const { upgradeWebSocket, websocket } = createBunWebSocket<ServerWebSocket>();
|
||||||
app.get("/chat-socket", upgradeWebSocket((c) => {
|
app.get("/chat-service", upgradeWebSocket((c) => {
|
||||||
return {
|
return {
|
||||||
|
onOpen(_event, ws) {
|
||||||
|
chatRoom.addListener('message-added', function (e) {
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
message: e.message.message,
|
||||||
|
chatter: e.message.chatter
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
},
|
||||||
onMessage(event, ws) {
|
onMessage(event, ws) {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
|
|
||||||
@ -29,8 +37,6 @@ app.get("/chat-socket", upgradeWebSocket((c) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
chatRoom.addMessage(message);
|
chatRoom.addMessage(message);
|
||||||
|
|
||||||
ws.send(JSON.stringify({ message: createMessageString(message) }));
|
|
||||||
},
|
},
|
||||||
onClose() {
|
onClose() {
|
||||||
console.log("Connection closed.");
|
console.log("Connection closed.");
|
||||||
@ -41,6 +47,20 @@ app.get("/chat-socket", upgradeWebSocket((c) => {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// set up the username, somehow
|
||||||
|
// set the session for a user
|
||||||
|
app.post("/login", async (c) => {
|
||||||
|
const user = await c.req.parseBody();
|
||||||
|
let success: boolean = false;
|
||||||
|
|
||||||
|
if (!users.find((u) => u == user.username)) {
|
||||||
|
users.push(user.username);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json({ success });
|
||||||
|
});
|
||||||
|
|
||||||
// get the HTML and JS from the static repo
|
// get the HTML and JS from the static repo
|
||||||
app.use("/", serveStatic({ path: "/static/index.html" }));
|
app.use("/", serveStatic({ path: "/static/index.html" }));
|
||||||
app.use("/*", serveStatic({ root: "/static" }));
|
app.use("/*", serveStatic({ root: "/static" }));
|
||||||
|
4
chat-app/static/css/main.css
Normal file
4
chat-app/static/css/main.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
input, label {
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.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>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/main.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user