diff options
author | WlodekM <[email protected]> | 2024-11-30 18:11:32 +0200 |
---|---|---|
committer | WlodekM <[email protected]> | 2024-11-30 18:11:32 +0200 |
commit | 97157622be86c68f69e6e48f3746ca2c70b7e8a8 (patch) | |
tree | 32fe8069343d2b41f01b2d58325942fb43864056 /BossDeer.html |
initial commit
Diffstat (limited to 'BossDeer.html')
-rw-r--r-- | BossDeer.html | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/BossDeer.html b/BossDeer.html new file mode 100644 index 0000000..e8b3a95 --- /dev/null +++ b/BossDeer.html @@ -0,0 +1,471 @@ +<!DOCTYPE html> +<html lang="en-US"><head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <title>BossDeer</title> + <meta name="apple-mobile-web-app-capable" content="yes"> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> + <meta charset="UTF-8"> + <style> + @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap'); + body { + font-family: 'Noto Sans', sans-serif; + margin: 0px; + background-color: #2e2d2b; + color: #ede4d5; + } + button { + background-color: #4d4a45; + color: #ede4d5; + border: none; + border-radius: 4px; + padding: 8px; + font-family: 'Noto Sans', sans-serif; + margin-bottom: 4px; + } + button:hover { + background-color: #403d39; + cursor: pointer; + } + input { + background-color: #403d39; + color: #ede4d5; + border: none; + border-radius: 4px; + padding: 8px; + font-family: 'Noto Sans', sans-serif; + margin-bottom: 4px; + } + .scene { + margin: 8px; + } + #error-bar { + background-color: #f2b149; + color: #2e2d2b; + width: 100%; + padding: 4px; + box-sizing: border-box; + } + .text-clickable { + text-decoration: underline; + cursor: pointer; + } + .hidden { + display: none; + } + .post { + background-color: #403d39; + padding: 6px; + border-radius: 4px; + margin-bottom: 8px; + } + .mono { + font-family: monospace; + } + #ms-msg { + width:70vw; + box-sizing: border-box; + } + #ms-button-post { + box-sizing: border-box; + } + .pfp { + border-radius: 100%; + width: 36px; + height: 36px; + float: left; + margin-right: 8px; + margin-top: 2px; + border: 2px #383531 solid; + } + a { + color: #ede4d5; + } + .attachment { + margin-left:4px; + margin-right:4px; + max-height:15vw; + } + .rl-guidelines { + background-color: #999085; + color: black; + border: none; + border-radius: 4px; + padding: 8px; + font-family: serif; + margin: 4px; + width: 90vw; + } + </style> + </head> + <body> + <div id="error-bar" class="hidden"><span onclick="closePopup();" class="text-clickable">Close</span> - <span id="error-text">Connecting...<span></span></span></div> + <div class="scene"> + <div id="loading" class="hidden"><center>Taking too long to load? Try <span onclick="logOut();" class="text-clickable">a full reset</span>.</center></div> + <div id="connection-lost" class="hidden"><center>Connection was lost.<br><span onclick="window.location.reload();" class="text-clickable">Reload</span>.</center></div> + <div id="register-login" class=""><center> + <input id="rl-username" placeholder="Username..." maxlength="20"><br> + <input id="rl-password" placeholder="Password..." type="password"><br> + <input id="rl-invitecode" placeholder="Invite code..." maxlength="16"><br> + <button onclick="logIn();">Log in</button> + <button onclick="register();">Register</button><br><br> + <small>(You only need to provide an invite code when registering.)<br>(Please ensure you have read the <a href="https://deer.meltland.dev/GUIDELINES.txt">GUIDELINES</a> (also provided below) before creating an account.)</small><br> + <embed class="rl-guidelines" type="text/plain" src="BossDeer_files/GUIDELINES.txt"><br> + <small id="rl-version">1.0.5b - SOKTDEER-2024.11.30-02.07</small> + </center></div> + <div id="main-scene" class="hidden"> + <button id="ms-name" disabled="disabled">@...</button> | <button onclick="switchScene('main-config');">Settings</button> <button onclick="alert('Not done yet!');">Inbox</button> <button id="ms-button-mod" class="hidden" onclick="switchScene('main-moderation');">Moderation</button><br> + <small id="ms-ulist">0 users online ()</small><br><br><center> + <button onclick="addAttachment();">+</button> <input id="ms-msg" maxlength="2000" onkeydown="if (event.keyCode == 13) {sendPost();}" placeholder="What's on your mind?"> <button id="ms-button-post" onclick="sendPost();">Post</button><br><small id="ms-details"></small></center><br> + <div id="ms-posts"><div class="post"><span><b>SoktDeer</b> (<span class="mono">@soktdeer</span>)</span><br><small>11/30/2024, 9:15:07 AM - <span class="text-clickable" onclick="reply(0);">Reply</span></small><br><span>Welcome to SoktDeer! Start chatting!</span></div></div> + </div> + <div id="main-config" class="hidden"> + <button onclick="switchScene('main-scene');">Return to Home</button><br> + <h2>Profile</h2> + <input id="mc-display-name" placeholder="Display name..." maxlength="20"> <button onclick="setDisplayName();">Set display name</button><br> + <input id="mc-avatar" placeholder="Avatar URL..." maxlength="656"> <button onclick="setAvatar();">Set avatar URL</button> + <h2>Misc</h2> + <button onclick="updateStg('moderation')">Toggle Moderation tab</button><br><br> + <button onclick="logOut();">Log out</button><br> + <small id="mc-version">1.0.5b - SOKTDEER-2024.11.30-02.07</small> + </div> + <div id="main-moderation" class="hidden"> + <button onclick="switchScene('main-scene');">Return to Home</button><br> + <h2>Ban</h2> + <input id="mm-username-ban" placeholder="Username..."><br> + <input id="mm-until-ban" type="datetime-local"><br> + <input id="mm-reason-ban" placeholder="Reason..."><br> + <button onclick="ban();">Ban User</button> + <h2>Invite code</h2> + <span id="mm-invite-code"></span><br> + <button onclick="genInviteCode();">Generate invite code</button><br> + <button onclick="resetInvites();">Reset invite codes</button> + </div> + </div> + + <script> +// hello guys gals and gays! +// keep in mind that unlike rome, this was infact built in a day +// so please dont judge so much! + +// let us commence and define the lame shit here + +document.getElementById("rl-username").value = ""; +document.getElementById("rl-password").value = ""; +document.getElementById("rl-invitecode").value = ""; + +function displayError (errText) { + document.getElementById("error-text").innerText = errText; + document.getElementById("error-bar").classList.remove("hidden"); +}; + +function closePopup () { + document.getElementById("error-bar").classList.add("hidden"); +}; + +const version = "1.0.5b"; +const serverVersion = "SOKTDEER-2024.11.30-02.07"; +let last_cmd = ""; +let username = ""; +let logged_in = false; +let scene = "loading"; +let ulist = []; +let posts = []; +let replies = []; +let attachments = []; + +if (localStorage.getItem("settings") == null) { + localStorage.setItem("settings", JSON.stringify({"moderation": false})) +}; + +let settings = JSON.parse(localStorage.getItem("settings")); + +function stgsTriggers() { + if (settings.moderation) { + document.getElementById("ms-button-mod").classList.remove("hidden"); + } else { + document.getElementById("ms-button-mod").classList.add("hidden"); + }; +}; + +function updateStg(setting) { + if (setting == "moderation") { + if (settings.moderation) { + settings.moderation = false; + } else { + settings.moderation = true; + }; + }; + localStorage.setItem("settings", JSON.stringify(settings)); + stgsTriggers(); +}; + +stgsTriggers(); + +// whatever, go my ws shit + +const ws = new WebSocket("wss://sokt.meltland.dev") // i hate const!! grr!! >:( + +ws.onmessage = function (event) { + let incoming = JSON.parse(event.data); + console.log(incoming); + + if (incoming.command == "greet") { + closePopup(); + document.getElementById("rl-version").innerText = `${version} - ${incoming.version}`; + document.getElementById("mc-version").innerText = `${version} - ${incoming.version}`; + if (incoming.version != serverVersion) { + displayError(`The server is on a different version than the client. Be wary of issues while using the client. (Expected "${serverVersion}", got "${incoming.version}")`); + }; + ulist = incoming.ulist; + document.getElementById("ms-ulist").innerText = `${ulist.length} users online (${ulist.toString().replaceAll(",", ", ")})`; + posts = incoming.messages; + for (const i in incoming.messages) { + loadPost(incoming.messages[i], true); + }; + if (localStorage.getItem("username") == null || localStorage.getItem("token") == null) { + scene = "register-login"; + document.getElementById("loading").classList.toggle("hidden"); + document.getElementById("register-login").classList.toggle("hidden") + } else { + username = localStorage.getItem("username"); + last_cmd = "login_token"; + ws.send(JSON.stringify({command: "login_token", username: username, token: localStorage.getItem("token")})) + }; + } else if (incoming.command == "ulist") { + ulist = incoming.ulist; + document.getElementById("ms-ulist").innerText = `${ulist.length} users online (${ulist.toString().replaceAll(",", ", ")})`; + }; + if ("error" in incoming) { + if (incoming.error) { + if (incoming.code == "banned") { + displayError(`Account is banned until ${new Date(incoming.banned_until * 1000).toLocaleString()} for "${incoming.ban_reason}"`) + } else { + displayError(`We hit an error. ("${incoming.code}" from ${incoming.form})`); + }; + } else if (last_cmd == "login_token" || last_cmd == "login_pswd") { + if (scene == "register-login") { + document.getElementById("register-login").classList.toggle("hidden"); + } else if (scene == "loading") { + document.getElementById("loading").classList.toggle("hidden"); + }; + scene = "main-scene"; + document.getElementById("main-scene").classList.toggle("hidden"); + document.getElementById("ms-name").innerText = `@${username}` + }; + }; + if ("token" in incoming && ["register","login_pswd"].includes(last_cmd)) { + localStorage.setItem("username", username); + localStorage.setItem("token", incoming.token); + if (last_cmd == "register") { + window.location.reload(); + }; + logged_in = true; + } else if (incoming.command == "new_post") { + loadPost(incoming.data, false); + } else if (last_cmd == "gen_invite" && "invite_code" in incoming) { + document.getElementById("mm-invite-code").innerText = `Your invite code is "${incoming.invite_code}". Use it on any SoktDeer client to sign up!\n\nCodes: ${incoming.invite_codes}` + }; +}; + +ws.onclose = function (event) { + switchScene("connection-lost"); +}; + +function switchScene (newScene) { + document.getElementById(scene).classList.toggle("hidden"); + document.getElementById(newScene).classList.toggle("hidden"); + scene = newScene; +}; + +function register() { + last_cmd = "register"; + username = document.getElementById("rl-username").value; + ws.send(JSON.stringify({command: "register", username: username, password: document.getElementById("rl-password").value, invite_code: document.getElementById("rl-invitecode").value})) +}; + +function logIn() { + last_cmd = "login_pswd"; + username = document.getElementById("rl-username").value; + ws.send(JSON.stringify({command: "login_pswd", username: username, password: document.getElementById("rl-password").value})) +}; + +function logOut() { + localStorage.clear(); + window.location.reload(); +}; + +function loadPost(resf, isFetch) { + console.log("Loading post " + resf.id) + var tsr = resf.created + var tsra = tsr * 1000 + var tsrb = Math.trunc(tsra) + var ts = new Date(); + ts.setTime(tsrb); + var sts = ts.toLocaleString(); + + var content = resf.content + for (const i in resf.replies) { + content = `→ ${resf.replies[i].author.display_name} (@${resf.replies[i].author.username}): ${resf.replies[i].content}\n${content}` + }; + + var post = document.createElement("div"); + post.classList.add("post"); + + if (resf.author.avatar) { + var avatar = document.createElement("img"); + avatar.src = resf.author.avatar; + avatar.classList.add("pfp"); + post.appendChild(avatar); + }; + + var postUsername = document.createElement("span"); + postUsername.innerHTML = `<b>${resf.author.display_name}</b> (<span class="mono">@${resf.author.username}</span>)`; + post.appendChild(postUsername); + + var breaklineA = document.createElement("br"); + post.appendChild(breaklineA); + + var postDetails = document.createElement("small"); + postDetails.innerHTML = `${sts} - <span class="text-clickable" onclick="reply(${resf.id});">Reply</span>`; + post.appendChild(postDetails); + + var breaklineB = document.createElement("br"); + post.appendChild(breaklineB); + + var postContent = document.createElement("span"); + postContent.innerText = content; + post.appendChild(postContent); + + if (resf.attachments.length != 0) { + var horline = document.createElement("hr"); + post.appendChild(horline); + + var attachmentDetails = document.createElement("span"); + for (const x in resf.attachments) { + attachmentDetails.innerHTML += `<a target="_blank" rel="noopener noreferrer" href="${resf.attachments[x]}">Attachment ${Number(x) + 1} (${resf.attachments[x]})</a><br>` + } + post.appendChild(attachmentDetails) + + // i love making garbage code because im too lazy to learn how to make things properly + + var attachmentA = document.createElement("img"); + attachmentA.src = resf.attachments[0] + attachmentA.classList.add("attachment") + attachmentA.setAttribute("onerror", "this.remove();") + post.appendChild(attachmentA); + + if (resf.attachments.length >= 2) { + var attachmentB = document.createElement("img"); + attachmentB.src = resf.attachments[1] + attachmentB.classList.add("attachment") + attachmentB.setAttribute("onerror", "this.remove();") + post.appendChild(attachmentB); + }; + + if (resf.attachments.length >= 3) { + var attachmentC = document.createElement("img"); + attachmentC.src = resf.attachments[2] + attachmentC.classList.add("attachment") + attachmentC.setAttribute("onerror", "this.remove();") + post.appendChild(attachmentC); + }; + }; + + if (isFetch) { + document.getElementById("ms-posts").appendChild(post); + } else { + document.getElementById("ms-posts").insertBefore(post, document.getElementById("ms-posts").firstChild); + } +}; + +function sendPost() { + last_cmd = "post"; + ws.send(JSON.stringify({command: "post", content: document.getElementById("ms-msg").value, replies: replies, attachments: attachments})) + document.getElementById("ms-msg").value = ""; + attachments = []; + replies = []; + updateDetailsMsg(); +}; + +function ban() { + last_cmd = "post"; + if (document.getElementById("mm-until-ban").value != "") { + var buntil = new Date(document.getElementById("mm-until-ban").value).getTime() / 1000 + } else { + var buntil = 0 + }; + ws.send(JSON.stringify({command: "ban", username: document.getElementById("mm-username-ban").value, banned_until: buntil, ban_reason: document.getElementById("mm-reason-ban").value})) + document.getElementById("mm-username-ban").value = ""; + document.getElementById("mm-until-ban").value = ""; + document.getElementById("mm-reason-ban").value = ""; +}; + +function genInviteCode() { + last_cmd = "gen_invite"; + ws.send(JSON.stringify({command: "gen_invite"})) +}; + +function resetInvites() { + last_cmd = "reset_invites"; + ws.send(JSON.stringify({command: "reset_invites"})) +}; + +function setDisplayName() { + last_cmd = "set_display_name"; + ws.send(JSON.stringify({command: "set_display_name", display_name: document.getElementById("mc-display-name").value})) + document.getElementById("mc-display-name").value = ""; +}; + +function setAvatar() { + last_cmd = "set_avatar"; + ws.send(JSON.stringify({command: "set_avatar", avatar: document.getElementById("mc-avatar").value})) + document.getElementById("mc-avatar").value = ""; +}; + +function updateDetailsMsg() { + if (replies.length == 0 && attachments.length == 0) { + document.getElementById("ms-details").innerText = "" + } else if (replies.length == 0) { + if (attachments.length == 1) {var plurals = ""} else {var plurals = "s"} + document.getElementById("ms-details").innerHTML = `${attachments.length} attachment${plurals} - <span class="text-clickable" onclick="clearAll();">Remove all</span>` + } else if (attachments.length == 0) { + if (replies.length == 1) {var plurals = "y"} else {var plurals = "ies"} + document.getElementById("ms-details").innerHTML = `${replies.length} repl${plurals} - <span class="text-clickable" onclick="clearAll();">Remove all</span>` + } else { + if (replies.length == 1) {var plurals = "y"} else {var plurals = "ies"} + if (attachments.length == 1) {var plurals_b = ""} else {var plurals_b = "s"} + document.getElementById("ms-details").innerHTML = `${replies.length} repl${plurals}, ${attachments.length} attachment${plurals_b} - <span class="text-clickable" onclick="clearAll();">Remove all</span>` + }; +}; + +function addAttachment() { + var ata = window.prompt("Add an attachment", "Put a whitelisted URL here...") + if (![null,""].includes(ata)) { + if (attachments.length != 3) { + attachments.push(ata); + }; + }; + updateDetailsMsg(); +}; + +function reply(id) { + if (replies.length != 3) { + replies.push(id); + }; + updateDetailsMsg(); +}; + +function clearAll() { + replies = []; + attachments = []; + updateDetailsMsg(); +}; + +function ping() { + ws.send(JSON.stringify({command: "ping"})) +}; + +setInterval(ping, 5000) + </script> + +</body></html> \ No newline at end of file |