add motd and links to bottom of webapp

This commit is contained in:
Elijah R 2024-07-12 14:33:17 -04:00
parent 7771251f4f
commit 8d04752f52
8 changed files with 149 additions and 12 deletions

View file

@ -18,6 +18,19 @@ adminPasswordHash = "f52fbd32b2b3b86ff88ef6c490628285f482af15ddcb29541f94bcf526a
[chat.ratelimits] [chat.ratelimits]
chat = {seconds = 10, limit = 8} chat = {seconds = 10, limit = 8}
[motd]
version = 1
html = """
<h2>Welcome to Agent Chat!</h2>
<h3>Rules</h3>
<ol>
<li>Do not break US federal law or the law of the State of New Jersey</li>
<li>Be respectful of everyone regardless of background or opinions. We have absolutely no tolerance for hate speech. Do not harass other users.</li>
<li>Do not post anything NSFW (porn, hentai, lewd imagery, etc). The posting of Child Sexual Abuse Material will result in an immediate ban and report to the National Center for Missing and Exploited Children</li>
<li>Do not spam in the chat and do not use bots without permission.</li>
</ol>
"""
[tts] [tts]
enabled = true enabled = true
# https://git.computernewb.com/computernewb/SAPIServer # https://git.computernewb.com/computernewb/SAPIServer

View file

@ -6,6 +6,7 @@ export interface IConfig {
} }
mysql: MySQLConfig; mysql: MySQLConfig;
chat: ChatConfig; chat: ChatConfig;
motd: motdConfig
tts: TTSConfig; tts: TTSConfig;
agents: AgentConfig[]; agents: AgentConfig[];
} }
@ -28,6 +29,11 @@ export interface ChatConfig {
} }
} }
export interface motdConfig {
version: number;
html: string;
}
export interface AgentConfig { export interface AgentConfig {
friendlyName: string; friendlyName: string;
filename: string; filename: string;

View file

@ -82,6 +82,18 @@ app.get("/api/agents", (req, res) => {
return config.agents; return config.agents;
}); });
// MOTD
app.get("/api/motd/version", (req, res) => {
res.header("Content-Type", "text/plain");
return config.motd.version.toString();
});
app.get("/api/motd/html", (req, res) => {
res.header("Content-Type", "text/html");
return config.motd.html;
});
let room = new MSAgentChatRoom(config.chat, config.agents, db, tts); let room = new MSAgentChatRoom(config.chat, config.agents, db, tts);
app.register(async app => { app.register(async app => {

View file

@ -19,6 +19,41 @@ body {
} }
} }
#motdContainer {
font-family: "Arial", sans-serif;
}
#bottomLinks {
font-family: "Pixelated MS Sans Serif", Arial;
li {
display: inline;
border-right: 1px solid black;
padding: 0;
margin: 0;
padding-right: 0.2rem;
margin-right: 0.2rem;
a {
font-size: 14pt;
color: #fff;
}
a:visited {
font-size: 14pt;
color: #fff;
}
}
li:last-child {
border-right: none;
padding-right: 0;
margin-right: 0;
}
list-style: none;
display: block;
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
#logonWindowLogo { #logonWindowLogo {
background-color: #ffffff; background-color: #ffffff;
margin: 0; margin: 0;

View file

@ -40,6 +40,22 @@
</form> </form>
</div> </div>
</div> </div>
<div class="window" id="motdWindow">
<div class="title-bar">
<div class="title-bar-text">
Welcome to Agent Chat
</div>
<div class="title-bar-controls">
<button aria-label="Close"></button>
</div>
</div>
<div class="window-body">
<div id="motdContainer"></div>
</div>
</div>
<ul id="bottomLinks">
<li><a href="#" id="rulesLink">Rules</a></li><li><a target="blank" href="https://discord.gg/a4kqb4mGyX">Discord</a></li><li><a target="blank" href="https://git.computernewb.com/computernewb/msagent-chat">Source Code</a></li>
</ul>
</div> </div>
<div id="chatView"> <div id="chatView">
<div id="chatBar"> <div id="chatBar">

View file

@ -1,7 +1,8 @@
export interface MSWindowConfig { export interface MSWindowConfig {
width: number, minWidth: number,
height: number, minHeight: number,
hasClose: boolean; maxWidth?: number | undefined,
maxHeight?: number | undefined,
startPosition: MSWindowStartPosition startPosition: MSWindowStartPosition
} }
@ -12,6 +13,7 @@ export enum MSWindowStartPosition {
export class MSWindow { export class MSWindow {
wnd: HTMLDivElement; wnd: HTMLDivElement;
closeBtn: HTMLButtonElement | undefined;
config: MSWindowConfig; config: MSWindowConfig;
titlebar: HTMLDivElement; titlebar: HTMLDivElement;
body: HTMLDivElement; body: HTMLDivElement;
@ -23,14 +25,27 @@ export class MSWindow {
this.shown = false; this.shown = false;
this.wnd = wnd; this.wnd = wnd;
this.config = config; this.config = config;
this.wnd.style.width = config.width + "px"; this.wnd.style.minWidth = config.minWidth + "px";
this.wnd.style.height = config.height + "px"; this.wnd.style.minHeight = config.minHeight + "px";
if (config.maxWidth) {
this.wnd.style.maxWidth = config.maxWidth + "px";
}
if (config.maxHeight) {
this.wnd.style.maxHeight = config.maxHeight + "px";
}
let titlebar = this.wnd.querySelector("div.title-bar"); let titlebar = this.wnd.querySelector("div.title-bar");
let body = this.wnd.querySelector("div.window-body"); let body = this.wnd.querySelector("div.window-body");
if (!titlebar || !body) if (!titlebar || !body)
throw new Error("MSWindow is missing titlebar or body element."); throw new Error("MSWindow is missing titlebar or body element.");
this.titlebar = titlebar as HTMLDivElement; this.titlebar = titlebar as HTMLDivElement;
this.body = body as HTMLDivElement; this.body = body as HTMLDivElement;
let closeBtn = this.titlebar.querySelector("div.title-bar-controls > button[aria-label='Close']") as HTMLButtonElement;
if (closeBtn) {
this.closeBtn = closeBtn;
closeBtn.addEventListener('click', () => {
this.hide();
});
}
// Register window move handlers // Register window move handlers
this.dragging = false; this.dragging = false;
switch (this.config.startPosition) { switch (this.config.startPosition) {
@ -40,8 +55,8 @@ export class MSWindow {
break; break;
} }
case MSWindowStartPosition.Center: { case MSWindowStartPosition.Center: {
this.x = (document.documentElement.clientWidth / 2) - (this.config.width / 2); this.x = (document.documentElement.clientWidth / 2) - (this.config.minWidth / 2);
this.y = (document.documentElement.clientHeight / 2) - (this.config.height / 2); this.y = (document.documentElement.clientHeight / 2) - (this.config.minHeight / 2);
break; break;
} }
default: { default: {
@ -79,8 +94,8 @@ export class MSWindow {
private setLoc() { private setLoc() {
if (this.x < 0) this.x = 0; if (this.x < 0) this.x = 0;
if (this.y < 0) this.y = 0; if (this.y < 0) this.y = 0;
if (this.x > document.documentElement.clientWidth - this.config.width) this.x = document.documentElement.clientWidth - this.config.width; if (this.x > document.documentElement.clientWidth - this.config.minWidth) this.x = document.documentElement.clientWidth - this.config.minWidth;
if (this.y > document.documentElement.clientHeight - this.config.height) this.y = document.documentElement.clientHeight - this.config.height; if (this.y > document.documentElement.clientHeight - this.config.minHeight) this.y = document.documentElement.clientHeight - this.config.minHeight;
this.wnd.style.top = this.y + "px"; this.wnd.style.top = this.y + "px";
this.wnd.style.left = this.x + "px"; this.wnd.style.left = this.x + "px";
} }

View file

@ -35,6 +35,11 @@ export interface APIAgentInfo {
filename: string; filename: string;
} }
export interface MOTD {
version: number;
html: string;
}
export class MSAgentClient { export class MSAgentClient {
private url: string; private url: string;
private socket: WebSocket | null; private socket: WebSocket | null;
@ -66,6 +71,21 @@ export class MSAgentClient {
return (await res.json()) as APIAgentInfo[]; return (await res.json()) as APIAgentInfo[];
} }
async getMotd(): Promise<MOTD> {
let res = await fetch(this.url + "/api/motd/version");
let vs = await res.text();
let version = parseInt(vs);
if (isNaN(version)) {
throw new Error("Version was NaN");
}
res = await fetch(this.url + "/api/motd/html");
let html = await res.text();
return {
version,
html
};
}
getUsers() { getUsers() {
return this.users; return this.users;
} }

View file

@ -4,6 +4,10 @@ import { MSAgentClient } from "./client.js";
const elements = { const elements = {
motdWindow: document.getElementById("motdWindow") as HTMLDivElement,
motdContainer: document.getElementById("motdContainer") as HTMLDivElement,
rulesLink: document.getElementById("rulesLink") as HTMLAnchorElement,
logonView: document.getElementById("logonView") as HTMLDivElement, logonView: document.getElementById("logonView") as HTMLDivElement,
logonWindow: document.getElementById("logonWindow") as HTMLDivElement, logonWindow: document.getElementById("logonWindow") as HTMLDivElement,
logonForm: document.getElementById("logonForm") as HTMLFormElement, logonForm: document.getElementById("logonForm") as HTMLFormElement,
@ -33,10 +37,16 @@ function roomInit() {
}); });
} }
let motdWindow = new MSWindow(elements.motdWindow, {
minWidth: 600,
minHeight: 300,
maxWidth: 600,
startPosition: MSWindowStartPosition.Center
});
let logonWindow = new MSWindow(elements.logonWindow, { let logonWindow = new MSWindow(elements.logonWindow, {
width: 500, minWidth: 500,
height: 275, minHeight: 275,
hasClose: false,
startPosition: MSWindowStartPosition.Center startPosition: MSWindowStartPosition.Center
}); });
@ -81,6 +91,16 @@ document.addEventListener('DOMContentLoaded', async () => {
option.value = agent.filename; option.value = agent.filename;
elements.agentSelect.appendChild(option); elements.agentSelect.appendChild(option);
} }
let motd = await Room.getMotd();
elements.motdContainer.innerHTML = motd.html;
let ver = localStorage.getItem("msagent-chat-motd-version");
if (!ver || parseInt(ver) !== motd.version) {
motdWindow.show();
localStorage.setItem("msagent-chat-motd-version", motd.version.toString());
}
elements.rulesLink.addEventListener('click', () => {
motdWindow.show();
})
}); });
function talk() { function talk() {