summary refs log tree commit diff
path: root/BossDeer.html
diff options
context:
space:
mode:
authorWlodekM <[email protected]>2024-11-30 18:11:32 +0200
committerWlodekM <[email protected]>2024-11-30 18:11:32 +0200
commit97157622be86c68f69e6e48f3746ca2c70b7e8a8 (patch)
tree32fe8069343d2b41f01b2d58325942fb43864056 /BossDeer.html
initial commit
Diffstat (limited to 'BossDeer.html')
-rw-r--r--BossDeer.html471
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