From 8fe0c9f46b6f8d792766ecccebfd504299d03395 Mon Sep 17 00:00:00 2001 From: MathMan05 Date: Sun, 30 Jun 2024 22:05:14 -0500 Subject: [PATCH] adds support for role settings and various fixes --- .dist/channel.js | 67 ++++++++++- .dist/guild.js | 48 ++++++++ .dist/index.js | 13 +- .dist/member.js | 53 ++++++++- .dist/message.js | 58 +++------ .dist/permissions.js | 22 +++- .dist/role.js | 9 ++ .dist/settings.js | 254 +++++++++++++++++++++++++++++++++++++++ .dist/user.js | 28 +++++ webpage/channel.ts | 70 ++++++++++- webpage/guild.ts | 53 ++++++++- webpage/index.html | 74 +++++------- webpage/index.ts | 15 +-- webpage/member.ts | 53 +++++++-- webpage/message.ts | 32 ++--- webpage/permissions.ts | 21 +++- webpage/role.ts | 10 +- webpage/settings.ts | 263 +++++++++++++++++++++++++++++++++++++++++ webpage/style.css | 207 ++++++++++++++++++++++++++++---- webpage/user.ts | 32 +++++ 20 files changed, 1199 insertions(+), 183 deletions(-) create mode 100644 .dist/settings.js create mode 100644 webpage/settings.ts diff --git a/.dist/channel.js b/.dist/channel.js index 1a4ff61..50f0467 100644 --- a/.dist/channel.js +++ b/.dist/channel.js @@ -5,6 +5,8 @@ import { Contextmenu } from "./contextmenu.js"; import { Fullscreen } from "./fullscreen.js"; import { markdown } from "./markdown.js"; import { Permissions } from "./permissions.js"; +import { Settings, RoleList } from "./settings.js"; +Settings; class Channel { editing; type; @@ -19,6 +21,7 @@ class Channel { guild_id; messageids; permission_overwrites; + permission_overwritesar; topic; nsfw; position; @@ -33,22 +36,38 @@ class Channel { static contextmenu = new Contextmenu("channel menu"); replyingto; static setupcontextmenu() { - Channel.contextmenu.addbutton("Copy channel id", function () { + this.contextmenu.addbutton("Copy channel id", function () { console.log(this); navigator.clipboard.writeText(this.id); }); - Channel.contextmenu.addbutton("Mark as read", function () { + this.contextmenu.addbutton("Mark as read", function () { console.log(this); this.readbottom(); }); - Channel.contextmenu.addbutton("Delete channel", function () { + this.contextmenu.addbutton("Settings[temp]", function () { + this.generateSettings(); + }); + this.contextmenu.addbutton("Delete channel", function () { console.log(this); this.deleteChannel(); }, null, _ => { console.log(_); return _.isAdmin(); }); - Channel.contextmenu.addbutton("Edit channel", function () { + this.contextmenu.addbutton("Edit channel", function () { this.editChannel(this); }, null, _ => { return _.isAdmin(); }); } + generateSettings() { + this.sortPerms(); + const settings = new Settings("Settings for " + this.name); + const s1 = settings.addButton("roles"); + s1.options.push(new RoleList(this.permission_overwritesar, this.guild, this.updateRolePermissions.bind(this), true)); + settings.show(); + } + sortPerms() { + this.permission_overwritesar.sort((a, b) => { + const order = this.guild.roles.findIndex(_ => _.id === a[0]) - this.guild.roles.findIndex(_ => _.id === b[0]); + return order; + }); + } constructor(JSON, owner) { if (JSON === -1) { return; @@ -66,8 +85,15 @@ class Channel { this.guild_id = JSON.guild_id; this.messageids = {}; this.permission_overwrites = {}; + this.permission_overwritesar = []; for (const thing of JSON.permission_overwrites) { + console.log(thing); + if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") { + continue; + } + ; this.permission_overwrites[thing.id] = new Permissions(thing.allow, thing.deny); + this.permission_overwritesar.push([thing.id, this.permission_overwrites[thing.id]]); } this.topic = JSON.topic; this.nsfw = JSON.nsfw; @@ -117,6 +143,9 @@ class Channel { return false; } get canMessage() { + if ((0 === this.permission_overwritesar.length) && this.hasPermission("MANAGE_CHANNELS")) { + this.addRoleToPerms(this.guild.roles.find(_ => _.name === "@everyone")); + } return this.hasPermission("SEND_MESSAGES"); } sortchildren() { @@ -726,6 +755,36 @@ class Channel { }); } } + async addRoleToPerms(role) { + await fetch(this.info.api.toString() + "/channels/" + this.id + "/permissions/" + role.id, { + method: "PUT", + headers: this.headers, + body: JSON.stringify({ + allow: "0", + deny: "0", + id: role.id, + type: 0 + }) + }); + const perm = new Permissions("0", "0"); + this.permission_overwrites[role.id] = perm; + this.permission_overwritesar.push([role.id, perm]); + } + async updateRolePermissions(id, perms) { + const permision = this.permission_overwrites[id]; + permision.allow = perms.allow; + permision.deny = perms.deny; + await fetch(this.info.api.toString() + "/channels/" + this.id + "/permissions/" + id, { + method: "PUT", + headers: this.headers, + body: JSON.stringify({ + allow: permision.allow.toString(), + deny: permision.deny.toString(), + id: id, + type: 0 + }) + }); + } } Channel.setupcontextmenu(); export { Channel }; diff --git a/.dist/guild.js b/.dist/guild.js index dc7b712..07afa58 100644 --- a/.dist/guild.js +++ b/.dist/guild.js @@ -3,6 +3,7 @@ import { Contextmenu } from "./contextmenu.js"; import { Role } from "./role.js"; import { Fullscreen } from "./fullscreen.js"; import { Member } from "./member.js"; +import { Settings, RoleList } from "./settings.js"; class Guild { owner; headers; @@ -42,6 +43,9 @@ class Guild { Guild.contextmenu.addbutton("Create invite", function () { console.log(this); }, null, _ => true, _ => false); + Guild.contextmenu.addbutton("Settings[temp]", function () { + this.generateSettings(); + }); /* -----things left for later----- guild.contextmenu.addbutton("Leave Guild",function(){ console.log(this) @@ -53,6 +57,16 @@ class Guild { },null,_=>{return thisuser.isAdmin()}) */ } + generateSettings() { + const settings = new Settings("Settings for " + this.properties.name); + const s1 = settings.addButton("roles"); + const permlist = []; + for (const thing of this.roles) { + permlist.push([thing.id, thing.permissions]); + } + s1.options.push(new RoleList(permlist, this, this.updateRolePermissions.bind(this))); + settings.show(); + } constructor(JSON, owner, member) { if (JSON === -1) { return; @@ -481,6 +495,40 @@ class Guild { body: JSON.stringify({ name: name, type: type }) }); } + async createRole(name) { + const fetched = await fetch(this.info.api.toString() + "/guilds/" + this.id + "roles", { + method: "POST", + headers: this.headers, + body: JSON.stringify({ + name: name, + color: 0, + permissions: "0" + }) + }); + const json = await fetched.json(); + const role = new Role(json, this); + this.roleids[role.id] = role; + this.roles.push(role); + return role; + } + async updateRolePermissions(id, perms) { + const role = this.roleids[id]; + role.permissions.allow = perms.allow; + role.permissions.deny = perms.deny; + await fetch(this.info.api.toString() + "/guilds/" + this.id + "/roles/" + this.id, { + method: "PATCH", + headers: this.headers, + body: JSON.stringify({ + color: role.color, + hoist: role.hoist, + icon: role.icon, + mentionable: role.mentionable, + name: role.name, + permissions: role.permissions.allow.toString(), + unicode_emoji: role.unicode_emoji, + }) + }); + } } Guild.setupcontextmenu(); export { Guild }; diff --git a/.dist/index.js b/.dist/index.js index a7aaf5b..02331b2 100644 --- a/.dist/index.js +++ b/.dist/index.js @@ -10,17 +10,6 @@ async function waitforload() { await res; } await waitforload(); -function setDynamicHeight() { - var servertdHeight = document.getElementById('servertd').offsetHeight + document.getElementById('typediv').offsetHeight + document.getElementById('pasteimage').offsetHeight; - document.documentElement.style.setProperty('--servertd-height', servertdHeight + 'px'); -} -const resizeObserver = new ResizeObserver(() => { - setDynamicHeight(); -}); -resizeObserver.observe(document.getElementById('servertd')); -resizeObserver.observe(document.getElementById('replybox')); -resizeObserver.observe(document.getElementById('pasteimage')); -setDynamicHeight(); const users = getBulkUsers(); if (!users.currentuser) { window.location.href = '/login.html'; @@ -101,7 +90,7 @@ thisuser.initwebsocket().then(_ => { } Contextmenu.currentmenu = table; console.log(table); - userdock.append(table); + userdock.before(table); event.stopImmediatePropagation(); }); } diff --git a/.dist/member.js b/.dist/member.js index 74a9c69..7bbaa83 100644 --- a/.dist/member.js +++ b/.dist/member.js @@ -1,11 +1,24 @@ import { User } from "./user.js"; import { Guild } from "./guild.js"; +import { Contextmenu } from "./contextmenu.js"; class Member { static already = {}; owner; user; roles; error; + static contextmenu = new Contextmenu("User Menu"); + static setUpContextMenu() { + this.contextmenu.addbutton("Copy user id", function () { + navigator.clipboard.writeText(this.id); + }); + this.contextmenu.addbutton("Message user", function () { + fetch(this.info.api.toString() + "/v9/users/@me/channels", { method: "POST", + body: JSON.stringify({ "recipients": [this.id] }), + headers: this.headers + }); + }); + } constructor(memberjson, owner, error = false) { this.error = error; this.owner = owner; @@ -54,8 +67,13 @@ class Member { console.error(guild); } let user; + let id = ""; if (unkown instanceof User) { user = unkown; + id = user.id; + } + else if (typeof unkown === typeof "") { + id = unkown; } else { return new Member(unkown, guild); @@ -66,26 +84,26 @@ class Member { if (!Member.already[guild.id]) { Member.already[guild.id] = {}; } - else if (Member.already[guild.id][user.id]) { - const memb = Member.already[guild.id][user.id]; + else if (Member.already[guild.id][id]) { + const memb = Member.already[guild.id][id]; if (memb instanceof Promise) { return await memb; } return memb; } - const promoise = fetch(guild.info.api.toString() + "/v9/users/" + user.id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.id, { headers: guild.headers }).then(_ => _.json()).then(json => { + const promoise = fetch(guild.info.api.toString() + "/v9/users/" + id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.id, { headers: guild.headers }).then(_ => _.json()).then(json => { const memb = new Member(json, guild); - Member.already[guild.id][user.id] = memb; + Member.already[guild.id][id] = memb; console.log("resolved"); return memb; }); - Member.already[guild.id][user.id] = promoise; + Member.already[guild.id][id] = promoise; try { return await promoise; } catch (_) { const memb = new Member(user, guild, true); - Member.already[guild.id][user.id] = memb; + Member.already[guild.id][id] = memb; return memb; } } @@ -115,5 +133,28 @@ class Member { } return this.guild.properties.owner_id === this.user.id; } + bind(html) { + if (html.tagName === "SPAN") { + if (!this) { + return; + } + ; + console.log(this.error); + if (this.error) { + const error = document.createElement("span"); + error.textContent = "!"; + error.classList.add("membererror"); + html.after(error); + return; + } + html.style.color = this.getColor(); + } + this.profileclick(html); + Member.contextmenu.bind(html); + } + profileclick(html) { + //to be implemented + } } +Member.setUpContextMenu(); export { Member }; diff --git a/.dist/message.js b/.dist/message.js index 1c3894c..64defe9 100644 --- a/.dist/message.js +++ b/.dist/message.js @@ -41,15 +41,6 @@ class Message { Message.contextmenu.addbutton("Copy message id", function () { navigator.clipboard.writeText(this.id); }); - Message.contextmenu.addbutton("Copy user id", function () { - navigator.clipboard.writeText(this.author.id); - }); - Message.contextmenu.addbutton("Message user", function () { - fetch(this.info.api.toString() + "/v9/users/@me/channels", { method: "POST", - body: JSON.stringify({ "recipients": [this.author.id] }), - headers: this.headers - }); - }); Message.contextmenu.addbutton("Edit", function () { this.channel.editing = this; document.getElementById("typebox").value = this.content; @@ -174,25 +165,26 @@ class Message { replyline.appendChild(username); const reply = document.createElement("div"); username.classList.add("username"); - Member.resolve(this.author, this.guild).then(_ => { - if (!_) { - return; - } - ; + this.author.bind(username, this.guild); + /* + Member.resolve(this.author,this.guild).then(_=>{ + if(!_) {return}; console.log(_.error); - if (_.error) { - username.textContent += "Error"; - alert("Should've gotten here"); - const error = document.createElement("span"); - error.textContent = "!"; + if(_.error){ + username.textContent+="Error"; + alert("Should've gotten here") + const error=document.createElement("span"); + error.textContent="!"; error.classList.add("membererror"); username.after(error); + return; } - username.style.color = _.getColor(); - }).catch(_ => { - console.log(_); + username.style.color=_.getColor(); + }).catch(_=>{ + console.log(_) }); + */ reply.classList.add("replytext"); replyline.appendChild(reply); const line2 = document.createElement("hr"); @@ -204,9 +196,9 @@ class Message { const author = message.author; reply.appendChild(markdown(message.content, { stdsize: true })); minipfp.src = author.getpfpsrc(); - author.profileclick(minipfp); + author.bind(minipfp); username.textContent = author.username; - author.profileclick(username); + author.bind(username); }); div.appendChild(replyline); } @@ -227,7 +219,7 @@ class Message { const combine = (premessage?.author?.id != this.author.id) || (current) || this.message_reference; if (combine) { const pfp = this.author.buildpfp(); - this.author.profileclick(pfp); + this.author.bind(pfp); pfpRow.appendChild(pfp); } else { @@ -242,21 +234,7 @@ class Message { if (combine) { const username = document.createElement("span"); username.classList.add("username"); - this.author.profileclick(username); - Member.resolve(this.author, this.guild).then(_ => { - if (!_) { - return; - } - ; - if (_.error) { - const error = document.createElement("span"); - error.textContent = "!"; - error.classList.add("membererror"); - username.after(error); - return; - } - username.style.color = _.getColor(); - }); + this.author.bind(username, this.guild); username.textContent = this.author.username; const userwrap = document.createElement("tr"); userwrap.appendChild(username); diff --git a/.dist/permissions.js b/.dist/permissions.js index 76d7bd9..010101e 100644 --- a/.dist/permissions.js +++ b/.dist/permissions.js @@ -2,7 +2,9 @@ export { Permissions }; class Permissions { allow; deny; + hasDeny; constructor(allow, deny = "") { + this.hasDeny = !!deny; this.allow = BigInt(allow); this.deny = BigInt(deny); } @@ -84,7 +86,7 @@ class Permissions { }, { name: "MANAGE_MESSAGES", - readableName: "Manager messages", + readableName: "Manage messages", description: "Allows the user to delete messages that aren't their own" }, { @@ -242,5 +244,23 @@ class Permissions { return 0; } } + setPermision(name, setto) { + const bit = Permissions.map[name]; + if (setto === 0) { + this.deny = this.setPermisionbit(bit, false, this.deny); + this.allow = this.setPermisionbit(bit, false, this.allow); + } + else if (setto === 1) { + this.deny = this.setPermisionbit(bit, false, this.deny); + this.allow = this.setPermisionbit(bit, true, this.allow); + } + else if (setto === -1) { + this.deny = this.setPermisionbit(bit, true, this.deny); + this.allow = this.setPermisionbit(bit, false, this.allow); + } + else { + console.error("invalid number entered:" + setto); + } + } } Permissions.makeMap(); diff --git a/.dist/role.js b/.dist/role.js index 8973e10..32a1bbb 100644 --- a/.dist/role.js +++ b/.dist/role.js @@ -5,7 +5,16 @@ class Role { owner; color; id; + name; + info; + hoist; + icon; + mentionable; + unicode_emoji; + headers; constructor(JSON, owner) { + this.headers = owner.headers; + this.info = owner.info; for (const thing of Object.keys(JSON)) { this[thing] = JSON[thing]; } diff --git a/.dist/settings.js b/.dist/settings.js new file mode 100644 index 0000000..42a4ead --- /dev/null +++ b/.dist/settings.js @@ -0,0 +1,254 @@ +import { Permissions } from "./permissions.js"; +class Buttons { + name; + buttons; + bigtable; + warndiv; + constructor(name) { + this.buttons = []; + this.name = name; + } + add(name, thing = undefined) { + if (!thing) { + thing = new Options(name, this); + } + this.buttons.push([name, thing]); + return thing; + } + generateHTML() { + const bigtable = document.createElement("div"); + bigtable.classList.add("Buttons"); + bigtable.classList.add("flexltr"); + this.bigtable = bigtable; + const htmlarea = document.createElement("div"); + const buttonTable = document.createElement("div"); + buttonTable.classList.add("flexttb", "settingbuttons"); + for (const thing of this.buttons) { + const button = document.createElement("button"); + button.classList.add("SettingsButton"); + button.textContent = thing[0]; + button.onclick = _ => { + this.generateHTMLArea(thing[1], htmlarea); + if (this.warndiv) { + this.warndiv.remove(); + } + }; + buttonTable.append(button); + } + this.generateHTMLArea(this.buttons[0][1], htmlarea); + bigtable.append(buttonTable); + bigtable.append(htmlarea); + return bigtable; + } + handleString(str) { + const div = document.createElement("div"); + div.textContent = str; + return div; + } + generateHTMLArea(genation, htmlarea) { + let html; + if (genation instanceof Options) { + html = genation.generateHTML(); + } + else { + html = this.handleString(genation); + } + htmlarea.innerHTML = ""; + htmlarea.append(html); + } + changed(html) { + this.warndiv = html; + this.bigtable.append(html); + } + save() { } +} +class PermisionToggle { + rolejson; + permissions; + owner; + constructor(roleJSON, permissions, owner) { + this.rolejson = roleJSON; + this.permissions = permissions; + this.owner = owner; + } + generateHTML() { + const div = document.createElement("div"); + div.classList.add("setting"); + const name = document.createElement("span"); + name.textContent = this.rolejson.readableName; + name.classList.add("settingsname"); + div.append(name); + div.append(this.generateCheckbox()); + const p = document.createElement("p"); + p.innerText = this.rolejson.description; + div.appendChild(p); + return div; + } + generateCheckbox() { + const div = document.createElement("div"); + div.classList.add("tritoggle"); + const state = this.permissions.getPermision(this.rolejson.name); + const on = document.createElement("input"); + on.type = "radio"; + on.name = this.rolejson.name; + div.append(on); + if (state === 1) { + on.checked = true; + } + ; + on.onclick = _ => { + this.permissions.setPermision(this.rolejson.name, 1); + this.owner.changed(); + }; + const no = document.createElement("input"); + no.type = "radio"; + no.name = this.rolejson.name; + div.append(no); + if (state === 0) { + no.checked = true; + } + ; + no.onclick = _ => { + this.permissions.setPermision(this.rolejson.name, 0); + this.owner.changed(); + }; + if (this.permissions.hasDeny) { + const off = document.createElement("input"); + off.type = "radio"; + off.name = this.rolejson.name; + div.append(off); + if (state === -1) { + off.checked = true; + } + ; + off.onclick = _ => { + this.permissions.setPermision(this.rolejson.name, -1); + this.owner.changed(); + }; + } + return div; + } +} +class RoleList extends Buttons { + permissions; + permission; + guild; + channel; + options; + onchange; + curid; + constructor(permissions, guild, onchange, channel = false) { + super("Roles"); + this.guild = guild; + this.permissions = permissions; + this.channel = channel; + this.onchange = onchange; + const options = new Options("", this); + if (channel) { + this.permission = new Permissions("0", "0"); + } + else { + this.permission = new Permissions("0"); + } + for (const thing of Permissions.info) { + options.addPermisionToggle(thing, this.permission); // + } + for (const i of permissions) { + this.buttons.push([guild.getRole(i[0]).name, i[0]]); // + } + this.options = options; + } + handleString(str) { + this.curid = str; + const perm = this.permissions.find(_ => _[0] === str)[1]; + this.permission.deny = perm.deny; + this.permission.allow = perm.allow; + this.options.name = this.guild.getRole(str).name; + this.options.haschanged = false; + return this.options.generateHTML(); + } + save() { + this.onchange(this.curid, this.permission); + } +} +class Options { + name; + haschanged = false; + options; + owner; + constructor(name, owner) { + this.name = name; + this.options = []; + this.owner = owner; + } + addPermisionToggle(roleJSON, permissions) { + this.options.push(new PermisionToggle(roleJSON, permissions, this)); + } + generateHTML() { + const div = document.createElement("div"); + div.classList.add("titlediv"); + const title = document.createElement("h2"); + title.textContent = this.name; + div.append(title); + title.classList.add("settingstitle"); + const table = document.createElement("div"); + table.classList.add("flexttb", "flexspace"); + for (const thing of this.options) { + table.append(thing.generateHTML()); + } + div.append(table); + return div; + } + changed() { + if (!this.haschanged) { + const div = document.createElement("div"); + div.classList.add("flexltr", "savediv"); + const span = document.createElement("span"); + div.append(span); + span.textContent = "Careful, you have unsaved changes"; + const button = document.createElement("button"); + button.textContent = "Save changes"; + div.append(button); + this.haschanged = true; + this.owner.changed(div); + button.onclick = _ => { + this.owner.save(); + div.remove(); + }; + } + } +} +class Settings extends Buttons { + static Buttons = Buttons; + static Options = Options; + html; + constructor(name) { + super(name); + } + addButton(name) { + const options = new Options(name, this); + this.add(name, options); + return options; + } + show() { + const background = document.createElement("div"); + background.classList.add("background"); + const title = document.createElement("h2"); + title.textContent = this.name; + title.classList.add("settingstitle"); + background.append(title); + background.append(this.generateHTML()); + const exit = document.createElement("span"); + exit.textContent = "✖"; + exit.classList.add("exitsettings"); + background.append(exit); + exit.onclick = _ => { this.hide(); }; + document.body.append(background); + this.html = background; + } + hide() { + this.html.remove(); + this.html = null; + } +} +export { Settings, RoleList }; diff --git a/.dist/user.js b/.dist/user.js index 5830f56..2323d78 100644 --- a/.dist/user.js +++ b/.dist/user.js @@ -13,6 +13,18 @@ class User { discriminator; pronouns; bot; + static contextmenu = new Contextmenu("User Menu"); + static setUpContextMenu() { + this.contextmenu.addbutton("Copy user id", function () { + navigator.clipboard.writeText(this.id); + }); + this.contextmenu.addbutton("Message user", function () { + fetch(this.info.api.toString() + "/v9/users/@me/channels", { method: "POST", + body: JSON.stringify({ "recipients": [this.id] }), + headers: this.headers + }); + }); + } static checkuser(userjson, owner) { if (User.userids[userjson.id]) { return User.userids[userjson.id]; @@ -60,6 +72,21 @@ class User { this.changepfp(json.avatar); } } + bind(html, guild = null) { + if (guild && guild.id !== "@me") { + Member.resolve(this, guild).then(_ => { + _.bind(html); + }).catch(_ => { + console.log(_); + }); + } + this.profileclick(html); + User.contextmenu.bind(html, this); + } + static async resolve(id, localuser) { + const json = await fetch(localuser.info.api.toString() + "/v9/users/" + id + "/profile", { headers: localuser.headers }).then(_ => _.json()); + return new User(json, localuser); + } changepfp(update) { this.avatar = update; this.hypotheticalpfp = false; @@ -137,4 +164,5 @@ class User { }; } } +User.setUpContextMenu(); export { User }; diff --git a/webpage/channel.ts b/webpage/channel.ts index 4ab0871..8537587 100644 --- a/webpage/channel.ts +++ b/webpage/channel.ts @@ -7,7 +7,9 @@ import {markdown} from "./markdown.js"; import {Guild} from "./guild.js"; import { Localuser } from "./localuser.js"; import { Permissions } from "./permissions.js"; - +import { Settings, RoleList } from "./settings.js"; +import { Role } from "./role.js"; +Settings; declare global { interface NotificationOptions { image?: string @@ -27,6 +29,7 @@ class Channel{ guild_id:string; messageids:{[key : string]:Message}; permission_overwrites:{[key:string]:Permissions}; + permission_overwritesar:[string,Permissions][] topic:string; nsfw:boolean; position:number; @@ -41,25 +44,44 @@ class Channel{ static contextmenu=new Contextmenu("channel menu"); replyingto:Message; static setupcontextmenu(){ - Channel.contextmenu.addbutton("Copy channel id",function(){ + this.contextmenu.addbutton("Copy channel id",function(){ console.log(this) navigator.clipboard.writeText(this.id); }); - Channel.contextmenu.addbutton("Mark as read",function(){ + this.contextmenu.addbutton("Mark as read",function(){ console.log(this) this.readbottom(); }); - Channel.contextmenu.addbutton("Delete channel",function(){ + this.contextmenu.addbutton("Settings[temp]",function(){ + this.generateSettings(); + }); + + this.contextmenu.addbutton("Delete channel",function(){ console.log(this) this.deleteChannel(); },null,_=>{console.log(_);return _.isAdmin()}); - Channel.contextmenu.addbutton("Edit channel",function(){ + this.contextmenu.addbutton("Edit channel",function(){ this.editChannel(this); },null,_=>{return _.isAdmin()}); } + generateSettings(){ + this.sortPerms(); + const settings=new Settings("Settings for "+this.name); + + const s1=settings.addButton("roles"); + + s1.options.push(new RoleList(this.permission_overwritesar,this.guild,this.updateRolePermissions.bind(this),true)) + settings.show(); + } + sortPerms(){ + this.permission_overwritesar.sort((a,b)=>{ + const order=this.guild.roles.findIndex(_=>_.id===a[0])-this.guild.roles.findIndex(_=>_.id===b[0]); + return order; + }) + } constructor(JSON,owner:Guild){ if(JSON===-1){ @@ -78,9 +100,14 @@ class Channel{ this.guild_id=JSON.guild_id; this.messageids={}; this.permission_overwrites={}; + this.permission_overwritesar=[]; for(const thing of JSON.permission_overwrites){ + console.log(thing); + if(thing.id==="1182819038095799904"||thing.id==="1182820803700625444"){continue;}; this.permission_overwrites[thing.id]=new Permissions(thing.allow,thing.deny); + this.permission_overwritesar.push([thing.id,this.permission_overwrites[thing.id]]); } + this.topic=JSON.topic; this.nsfw=JSON.nsfw; this.position=JSON.position; @@ -127,6 +154,9 @@ class Channel{ return false; } get canMessage():boolean{ + if((0===this.permission_overwritesar.length)&&this.hasPermission("MANAGE_CHANNELS")){ + this.addRoleToPerms(this.guild.roles.find(_=>_.name==="@everyone")); + } return this.hasPermission("SEND_MESSAGES"); } sortchildren(){ @@ -717,6 +747,36 @@ class Channel{ }); } } + async addRoleToPerms(role:Role){ + await fetch(this.info.api.toString()+"/channels/"+this.id+"/permissions/"+role.id,{ + method:"PUT", + headers:this.headers, + body:JSON.stringify({ + allow:"0", + deny:"0", + id:role.id, + type:0 + }) + }) + const perm=new Permissions("0","0"); + this.permission_overwrites[role.id]=perm; + this.permission_overwritesar.push([role.id,perm]); + } + async updateRolePermissions(id:string,perms:Permissions){ + const permision=this.permission_overwrites[id]; + permision.allow=perms.allow; + permision.deny=perms.deny; + await fetch(this.info.api.toString()+"/channels/"+this.id+"/permissions/"+id,{ + method:"PUT", + headers:this.headers, + body:JSON.stringify({ + allow:permision.allow.toString(), + deny:permision.deny.toString(), + id:id, + type:0 + }) + }) + } } Channel.setupcontextmenu(); export {Channel}; diff --git a/webpage/guild.ts b/webpage/guild.ts index 1db660c..428adb2 100644 --- a/webpage/guild.ts +++ b/webpage/guild.ts @@ -4,7 +4,8 @@ import {Contextmenu} from "./contextmenu.js"; import {Role} from "./role.js"; import {Fullscreen} from "./fullscreen.js"; import {Member} from "./member.js"; - +import {Settings,RoleList} from "./settings.js"; +import {Permissions} from "./permissions.js"; class Guild{ owner:Localuser; headers:Localuser["headers"]; @@ -49,6 +50,9 @@ class Guild{ Guild.contextmenu.addbutton("Create invite",function(){ console.log(this); },null,_=>true,_=>false); + Guild.contextmenu.addbutton("Settings[temp]",function(){ + this.generateSettings(); + }); /* -----things left for later----- guild.contextmenu.addbutton("Leave Guild",function(){ console.log(this) @@ -60,6 +64,17 @@ class Guild{ },null,_=>{return thisuser.isAdmin()}) */ } + generateSettings(){ + const settings=new Settings("Settings for "+this.properties.name); + + const s1=settings.addButton("roles"); + const permlist=[]; + for(const thing of this.roles){ + permlist.push([thing.id,thing.permissions]); + } + s1.options.push(new RoleList(permlist,this,this.updateRolePermissions.bind(this))); + settings.show(); + } constructor(JSON,owner:Localuser,member){ if(JSON===-1){ @@ -92,6 +107,7 @@ class Guild{ this.headchannels.push(thing); } } + } notisetting(settings){ this.message_notifications=settings.message_notifications; @@ -489,6 +505,41 @@ class Guild{ body:JSON.stringify({name: name, type: type}) }) } + async createRole(name:string){ + const fetched=await fetch(this.info.api.toString()+"/guilds/"+this.id+"roles",{ + method:"POST", + headers:this.headers, + body:JSON.stringify({ + name:name, + color:0, + permissions:"0" + }) + }) + const json=await fetched.json(); + const role=new Role(json,this); + this.roleids[role.id]=role; + this.roles.push(role); + return role; + } + async updateRolePermissions(id:string,perms:Permissions){ + const role=this.roleids[id]; + role.permissions.allow=perms.allow; + role.permissions.deny=perms.deny; + + await fetch(this.info.api.toString()+"/guilds/"+this.id+"/roles/"+this.id,{ + method:"PATCH", + headers:this.headers, + body:JSON.stringify({ + color:role.color, + hoist:role.hoist, + icon:role.icon, + mentionable:role.mentionable, + name:role.name, + permissions:role.permissions.allow.toString(), + unicode_emoji:role.unicode_emoji, + }) + }) + } } Guild.setupcontextmenu(); export { Guild }; diff --git a/webpage/index.html b/webpage/index.html index 8f3689d..4ea6348 100644 --- a/webpage/index.html +++ b/webpage/index.html @@ -13,51 +13,40 @@

Jank Client is loading

This shouldn't take long

- - - - - + +
+
+
+ -
- - - - - -
-
-
+
+
+
+
+
+

Server Name

-
- Channel -
-
- - - - - -
- - - -
- - -
-

USERNAME

-

SATUS

-
-
-

-
+
+

USERNAME

+

SATUS

+
-
+

+ + +
+
+ Channel +
+
-
-
-
+
+
+
+
-
-
-
+ + + diff --git a/webpage/index.ts b/webpage/index.ts index a5db54c..a5d367e 100644 --- a/webpage/index.ts +++ b/webpage/index.ts @@ -1,6 +1,7 @@ import { Localuser } from "./localuser.js"; import {Contextmenu} from "./contextmenu.js"; import {mobile, getBulkUsers,setTheme, Specialuser} from "./login.js"; + async function waitforload(){ let res new Promise(r=>{res=r}); @@ -11,17 +12,7 @@ async function waitforload(){ } await waitforload(); -function setDynamicHeight() { - var servertdHeight = document.getElementById('servertd').offsetHeight+document.getElementById('typediv').offsetHeight+document.getElementById('pasteimage').offsetHeight; - document.documentElement.style.setProperty('--servertd-height', servertdHeight + 'px'); -} -const resizeObserver = new ResizeObserver(() => { - setDynamicHeight(); -}); -resizeObserver.observe(document.getElementById('servertd')); -resizeObserver.observe(document.getElementById('replybox')); -resizeObserver.observe(document.getElementById('pasteimage')); -setDynamicHeight(); + const users=getBulkUsers(); if(!users.currentuser){ @@ -109,7 +100,7 @@ thisuser.initwebsocket().then(_=>{ } Contextmenu.currentmenu=table; console.log(table); - userdock.append(table); + userdock.before(table); event.stopImmediatePropagation(); }) } diff --git a/webpage/member.ts b/webpage/member.ts index 6b5a3c4..b155092 100644 --- a/webpage/member.ts +++ b/webpage/member.ts @@ -1,12 +1,27 @@ import {User} from "./user.js"; import {Role} from "./role.js"; import {Guild} from "./guild.js"; +import { Contextmenu } from "./contextmenu.js"; + class Member{ static already={}; owner:Guild; user:User; roles:Role[]; error:boolean; + static contextmenu:Contextmenu=new Contextmenu("User Menu"); + static setUpContextMenu(){ + this.contextmenu.addbutton("Copy user id",function(){ + navigator.clipboard.writeText(this.id); + }); + this.contextmenu.addbutton("Message user",function(){ + fetch(this.info.api.toString()+"/v9/users/@me/channels", + {method:"POST", + body:JSON.stringify({"recipients":[this.id]}), + headers: this.headers + }); + }); + } constructor(memberjson,owner:Guild,error=false){ this.error=error; this.owner=owner; @@ -45,38 +60,42 @@ class Member{ get info(){ return this.owner.info; } - static async resolve(unkown:User|object,guild:Guild):Promise{ + static async resolve(unkown:User|object|string,guild:Guild):Promise{ if(!(guild instanceof Guild)){ console.error(guild) } let user:User; + let id=""; if(unkown instanceof User){ user=unkown as User; + id=user.id; + }else if(typeof unkown===typeof ""){ + id=unkown as string; }else{ return new Member(unkown,guild); } if(guild.id==="@me"){return null} if(!Member.already[guild.id]){ Member.already[guild.id]={}; - }else if(Member.already[guild.id][user.id]){ - const memb=Member.already[guild.id][user.id] + }else if(Member.already[guild.id][id]){ + const memb=Member.already[guild.id][id] if(memb instanceof Promise){ return await memb; } return memb; } - const promoise= fetch(guild.info.api.toString()+"/v9/users/"+user.id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+guild.id,{headers:guild.headers}).then(_=>_.json()).then(json=>{ + const promoise= fetch(guild.info.api.toString()+"/v9/users/"+id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+guild.id,{headers:guild.headers}).then(_=>_.json()).then(json=>{ const memb=new Member(json,guild); - Member.already[guild.id][user.id]=memb; + Member.already[guild.id][id]=memb; console.log("resolved") return memb }) - Member.already[guild.id][user.id]=promoise; + Member.already[guild.id][id]=promoise; try{ return await promoise }catch(_){ const memb=new Member(user,guild,true); - Member.already[guild.id][user.id]=memb; + Member.already[guild.id][id]=memb; return memb; } } @@ -105,7 +124,27 @@ class Member{ } } return this.guild.properties.owner_id===this.user.id; + } + bind(html:HTMLElement){ + if(html.tagName==="SPAN"){ + if(!this) {return}; + console.log(this.error); + if(this.error){ + const error=document.createElement("span"); + error.textContent="!"; + error.classList.add("membererror"); + html.after(error); + return; + } + html.style.color=this.getColor(); + } + this.profileclick(html); + Member.contextmenu.bind(html); + } + profileclick(html:HTMLElement){ + //to be implemented } } +Member.setUpContextMenu(); export {Member}; diff --git a/webpage/message.ts b/webpage/message.ts index 27f3f41..c79d8f5 100644 --- a/webpage/message.ts +++ b/webpage/message.ts @@ -46,16 +46,6 @@ class Message{ Message.contextmenu.addbutton("Copy message id",function(){ navigator.clipboard.writeText(this.id); }); - Message.contextmenu.addbutton("Copy user id",function(){ - navigator.clipboard.writeText(this.author.id); - }); - Message.contextmenu.addbutton("Message user",function(){ - fetch(this.info.api.toString()+"/v9/users/@me/channels", - {method:"POST", - body:JSON.stringify({"recipients":[this.author.id]}), - headers: this.headers - }); - }) Message.contextmenu.addbutton("Edit",function(){ this.channel.editing=this; (document.getElementById("typebox") as HTMLInputElement).value=this.content; @@ -179,7 +169,9 @@ class Message{ replyline.appendChild(username); const reply=document.createElement("div"); username.classList.add("username"); + this.author.bind(username,this.guild); + /* Member.resolve(this.author,this.guild).then(_=>{ if(!_) {return}; console.log(_.error); @@ -197,6 +189,7 @@ class Message{ }).catch(_=>{ console.log(_) }); + */ reply.classList.add("replytext"); replyline.appendChild(reply); @@ -209,9 +202,9 @@ class Message{ const author=message.author; reply.appendChild(markdown(message.content,{stdsize:true})); minipfp.src=author.getpfpsrc() - author.profileclick(minipfp) + author.bind(minipfp); username.textContent=author.username; - author.profileclick(username) + author.bind(username); }); div.appendChild(replyline); } @@ -234,7 +227,7 @@ class Message{ const combine=(premessage?.author?.id!=this.author.id)||(current)||this.message_reference if(combine){ const pfp=this.author.buildpfp(); - this.author.profileclick(pfp); + this.author.bind(pfp); pfpRow.appendChild(pfp); }else{ div["pfpparent"]=pfpparent; @@ -249,19 +242,8 @@ class Message{ if(combine){ const username=document.createElement("span"); username.classList.add("username") - this.author.profileclick(username); - Member.resolve(this.author,this.guild).then(_=>{ - if(!_) {return}; - if(_.error){ - const error=document.createElement("span"); - error.textContent="!"; - error.classList.add("membererror"); - username.after(error); + this.author.bind(username,this.guild); - return; - } - username.style.color=_.getColor(); - }) username.textContent=this.author.username; const userwrap=document.createElement("tr") userwrap.appendChild(username) diff --git a/webpage/permissions.ts b/webpage/permissions.ts index 9144527..28f7506 100644 --- a/webpage/permissions.ts +++ b/webpage/permissions.ts @@ -2,7 +2,9 @@ export {Permissions}; class Permissions{ allow:bigint; deny:bigint; + readonly hasDeny:boolean; constructor(allow:string,deny:string=""){ + this.hasDeny=!!deny; this.allow=BigInt(allow); this.deny=BigInt(deny); } @@ -86,7 +88,7 @@ class Permissions{ }, { name:"MANAGE_MESSAGES", - readableName:"Manager messages", + readableName:"Manage messages", description:"Allows the user to delete messages that aren't their own" }, { @@ -242,5 +244,22 @@ class Permissions{ return 0; } } + setPermision(name:string,setto:number):void{ + const bit=Permissions.map[name] as number; + if(setto===0){ + this.deny=this.setPermisionbit(bit,false,this.deny); + this.allow=this.setPermisionbit(bit,false,this.allow); + }else if(setto===1){ + + this.deny=this.setPermisionbit(bit,false,this.deny); + this.allow=this.setPermisionbit(bit,true,this.allow); + }else if(setto===-1){ + + this.deny=this.setPermisionbit(bit,true,this.deny); + this.allow=this.setPermisionbit(bit,false,this.allow); + }else{ + console.error("invalid number entered:"+setto); + } + } } Permissions.makeMap(); diff --git a/webpage/role.ts b/webpage/role.ts index f50a69b..9a1145c 100644 --- a/webpage/role.ts +++ b/webpage/role.ts @@ -7,7 +7,16 @@ class Role{ owner:Guild; color:number; id:string; + name:string; + info:Guild["info"]; + hoist:boolean; + icon:string; + mentionable:boolean; + unicode_emoji:string; + headers:Guild["headers"]; constructor(JSON, owner:Guild){ + this.headers=owner.headers; + this.info=owner.info; for(const thing of Object.keys(JSON)){ this[thing]=JSON[thing]; } @@ -24,5 +33,4 @@ class Role{ if(this.color===0){return null}; return `#${this.color.toString(16)}`; } - } diff --git a/webpage/settings.ts b/webpage/settings.ts new file mode 100644 index 0000000..29b7ddf --- /dev/null +++ b/webpage/settings.ts @@ -0,0 +1,263 @@ +import { Permissions } from "./permissions.js"; +import { Guild } from "./guild.js"; + +class Buttons{ + readonly name:string; + readonly buttons:[string,Options|string][]; + bigtable:HTMLDivElement; + warndiv:HTMLElement; + constructor(name:string){ + this.buttons=[]; + this.name=name; + } + add(name:string,thing:Options=undefined){ + if(!thing){thing=new Options(name,this)} + this.buttons.push([name,thing]); + return thing; + } + generateHTML(){ + const bigtable=document.createElement("div"); + bigtable.classList.add("Buttons"); + bigtable.classList.add("flexltr"); + this.bigtable=bigtable; + const htmlarea=document.createElement("div"); + + const buttonTable=document.createElement("div"); + buttonTable.classList.add("flexttb","settingbuttons"); + for(const thing of this.buttons){ + const button=document.createElement("button"); + button.classList.add("SettingsButton"); + button.textContent=thing[0]; + button.onclick=_=>{ + this.generateHTMLArea(thing[1],htmlarea); + if(this.warndiv){ + this.warndiv.remove(); + } + } + buttonTable.append(button); + } + this.generateHTMLArea(this.buttons[0][1],htmlarea); + bigtable.append(buttonTable); + bigtable.append(htmlarea); + return bigtable; + } + handleString(str:string):HTMLElement{ + const div=document.createElement("div"); + div.textContent=str; + return div; + } + private generateHTMLArea(genation:Options|string,htmlarea:HTMLElement){ + let html:HTMLElement; + if(genation instanceof Options){ + html=genation.generateHTML(); + }else{ + html=this.handleString(genation); + } + htmlarea.innerHTML=""; + htmlarea.append(html); + } + changed(html:HTMLElement){ + this.warndiv=html; + this.bigtable.append(html); + } + save(){} +} + +class PermisionToggle{ + readonly rolejson:{name:string,readableName:string,description:string}; + permissions:Permissions; + owner:Options; + constructor(roleJSON:PermisionToggle["rolejson"],permissions:Permissions,owner:Options){ + this.rolejson=roleJSON; + this.permissions=permissions; + this.owner=owner; + } + generateHTML():HTMLElement{ + const div=document.createElement("div"); + div.classList.add("setting"); + const name=document.createElement("span"); + name.textContent=this.rolejson.readableName; + name.classList.add("settingsname"); + div.append(name); + + + div.append(this.generateCheckbox()); + const p=document.createElement("p"); + p.innerText=this.rolejson.description; + div.appendChild(p); + return div; + } + generateCheckbox():HTMLElement{ + const div=document.createElement("div"); + div.classList.add("tritoggle"); + const state=this.permissions.getPermision(this.rolejson.name); + + const on=document.createElement("input"); + on.type="radio"; + on.name=this.rolejson.name; + div.append(on); + if(state===1){on.checked=true;}; + on.onclick=_=>{ + this.permissions.setPermision(this.rolejson.name,1); + this.owner.changed(); + } + + const no=document.createElement("input"); + no.type="radio"; + no.name=this.rolejson.name; + div.append(no); + if(state===0){no.checked=true;}; + no.onclick=_=>{ + this.permissions.setPermision(this.rolejson.name,0); + this.owner.changed(); + } + if(this.permissions.hasDeny){ + const off=document.createElement("input"); + off.type="radio"; + off.name=this.rolejson.name; + div.append(off); + if(state===-1){off.checked=true;}; + off.onclick=_=>{ + this.permissions.setPermision(this.rolejson.name,-1); + this.owner.changed(); + } + } + return div; + } +} +class RoleList extends Buttons{ + readonly permissions:[string,Permissions][]; + permission:Permissions; + readonly guild:Guild; + readonly channel:boolean; + readonly declare buttons:[string,string][]; + readonly options:Options; + onchange:Function; + curid:string; + constructor(permissions:[string,Permissions][],guild:Guild,onchange:Function,channel=false){ + super("Roles"); + this.guild=guild; + this.permissions=permissions; + this.channel=channel; + this.onchange=onchange; + const options=new Options("",this); + if(channel){ + this.permission=new Permissions("0","0"); + }else{ + this.permission=new Permissions("0"); + } + for(const thing of Permissions.info){ + options.addPermisionToggle(thing,this.permission);// + } + for(const i of permissions){ + this.buttons.push([guild.getRole(i[0]).name,i[0]])// + } + this.options=options; + } + handleString(str:string):HTMLElement{ + this.curid=str; + const perm=this.permissions.find(_=>_[0]===str)[1]; + this.permission.deny=perm.deny; + this.permission.allow=perm.allow; + this.options.name=this.guild.getRole(str).name; + this.options.haschanged=false; + return this.options.generateHTML(); + } + save(){ + this.onchange(this.curid,this.permission); + } +} +class Options{ + name:string; + haschanged=false; + readonly options:(PermisionToggle|Buttons|RoleList)[]; + readonly owner:Buttons; + + constructor(name:string,owner:Buttons){ + this.name=name; + this.options=[]; + this.owner=owner; + + } + addPermisionToggle(roleJSON:PermisionToggle["rolejson"],permissions:Permissions){ + this.options.push(new PermisionToggle(roleJSON,permissions,this)); + } + generateHTML():HTMLElement{ + const div=document.createElement("div"); + div.classList.add("titlediv"); + const title=document.createElement("h2"); + title.textContent=this.name; + div.append(title); + title.classList.add("settingstitle") + const table=document.createElement("div"); + table.classList.add("flexttb","flexspace"); + for(const thing of this.options){ + table.append(thing.generateHTML()); + } + div.append(table); + return div; + } + changed(){ + + if(!this.haschanged){ + const div=document.createElement("div"); + div.classList.add("flexltr","savediv"); + const span=document.createElement("span"); + div.append(span); + span.textContent="Careful, you have unsaved changes"; + const button=document.createElement("button"); + button.textContent="Save changes"; + div.append(button); + this.haschanged=true; + this.owner.changed(div); + + button.onclick=_=>{ + this.owner.save(); + div.remove(); + } + } + } +} + + + +class Settings extends Buttons{ + static readonly Buttons=Buttons; + static readonly Options=Options; + html:HTMLElement; + constructor(name:string){ + super(name); + } + addButton(name:string):Options{ + const options=new Options(name,this); + this.add(name,options); + return options; + } + show(){ + const background=document.createElement("div"); + background.classList.add("background"); + + const title=document.createElement("h2"); + title.textContent=this.name; + title.classList.add("settingstitle") + background.append(title); + + background.append(this.generateHTML()); + + + + const exit=document.createElement("span"); + exit.textContent="✖"; + exit.classList.add("exitsettings"); + background.append(exit); + exit.onclick=_=>{this.hide();}; + document.body.append(background); + this.html=background; + } + hide(){ + this.html.remove(); + this.html=null; + } +} +export {Settings,RoleList} + diff --git a/webpage/style.css b/webpage/style.css index 6da3c81..e8a90bb 100644 --- a/webpage/style.css +++ b/webpage/style.css @@ -5,6 +5,7 @@ body { color: var(--primary-text); overflow-y: hidden; overflow-x: hidden; + height:100%; margin: 0; padding: 0; } @@ -52,10 +53,13 @@ th { .background { position: absolute; width: 100%; - height: 100%; + height: 100vh; top: 0; background-color: #000000bf; z-index: 11; + max-height: 100%; + display: flex; + flex-direction: column; } .messagediv:hover { @@ -177,7 +181,7 @@ h2 { #neunence { vertical-align: top; overflow: auto; - height: 9dvh; + flex-shrink: 0; } #servers { @@ -235,14 +239,16 @@ img { #messagecontainer { overflow: auto; - height: 100%; - width: 100%; - display: inline-block; + display: flex; max-width: 100%; + flex-shrink: 1; + width: 100%; + /* flex-grow: 1; */ } #messages { max-width: 100%; + /* height: 100%; */ } p { @@ -253,14 +259,17 @@ p { } #channels { - --top-height: 28px; background-color: var(--channels-bg); - position: absolute; top: var(--top-height); - height: calc(100dvh - 53px - var(--top-height)); - width: 2.5in; overflow: auto; user-select: none; + flex-grow: 1; + /* display: flex; */ + flex-shrink: 1; + min-height: 0px; + min-width: 0px; + width: 2.5in; + /* height: 100%; */ } #userdock { @@ -308,10 +317,12 @@ div { font-size: 16px; padding: 3px; border-radius: .25cm; - width: 99%; + width: 100%; height: .5in; z-index: -100; max-width: 99%; + display: flex; + max-height: fit-content; } p { @@ -369,6 +380,7 @@ p { #typediv { position: relative; + /* display: flex; */ } .loading-indicator { @@ -451,10 +463,14 @@ p { } #channelw { width: 100%; - display: inline-block; + display: flex; grid-template-rows: auto 1fr; - height: calc(100dvh - .1in - var(--servertd-height)); max-width: 100%; + flex-direction: column; + flex-shrink: 1; + min-height: 0; + height: 100%; + /* width: 100%; */ } .timestamp { @@ -586,7 +602,11 @@ textarea { border-color: var(--server-border); border-width: .1cm; border-style: solid; - height: .2in; + height: .4in; + display: flex; + flex-direction: column; + justify-content: space-evenly; + flex-shrink: 0; } .channeleffects { @@ -628,13 +648,24 @@ textarea { #userdock { background-color: var(--user-dock-bg); width: 2.5in; - position: absolute; - bottom: 0; - /* position: absolute; */ + position: relative; + flex-shrink: 0; + height: .6in; + display: flex; + align-content: stretch; + /* flex-direction: row; */ + justify-content: space-between; + align-items: center; + padding-top: .02in; } #channels-td { padding-right: 240px; + flex-grow: 1; + display: flex; + flex-direction: column; + height: 100%; + flex-shrink: 1; } #settings { @@ -646,6 +677,7 @@ textarea { font-size: .25in; width: .3in; height: .3in; + overflow: visible; } #settings:hover { @@ -659,11 +691,13 @@ textarea { background-color: var(--user-info-bg); border-radius: .1in; cursor: pointer; + flex-shrink: 0; + padding: .03in; } .servernamediv { - width: 100%; - max-width: 100%; + /* width: 100%; */ + /* max-width: 100%; */ } button { @@ -908,13 +942,14 @@ span { .accountSwitcher{ background:var(--profile-bg); cursor:pointer; - position:absolute; - top:0px; - transform: translate(0, -100%); - /* width:100%; */ box-shadow: .00in -.5in 1in #0000006b; border-radius: .05in .05in .0in.0in; - /* max-width: 100%; */ + flex-grow: 0; + align-self: center; + flex-shrink: 1; + min-width: 0px; + display: inline-block; + width: 100%; } .accountSwitcher tr{ transition: background .3s; @@ -932,6 +967,7 @@ span { word-break: normal; white-space: nowrap; font-size: .125in; + min-width: 0px; } .title{ font-size:.25in; @@ -941,6 +977,7 @@ span { #channelname{ font-size:.2in; font-weight:bold; + display: flex; } #mobileback{ /* display:inline-block; */ @@ -1051,9 +1088,10 @@ span { right:0px; } .containedFile{ - position:relative !important; + position: relative; width: fit-content; box-shadow:.02in .02in .05in black; + display: inline-block; } #replybox{ display:flex; @@ -1083,3 +1121,124 @@ span { height: 0in; padding: 0in; } +.Buttons{ + background:var(--primary-bg); + position: relative; +} +.flexltr{ + display:flex; + flex-wrap: nowrap; + flex-direction: row; + max-height: 100%; + overflow: auto; +} +.flexttb{ + display: flex; + flex-direction: column; + max-height: 100vh; + overflow: auto; + /* margin-bottom: 1in; */ + /* padding-bottom: .1in; */ +} +.settingbuttons{ + padding-top:.075in; + width: 4in; + border-right: solid var(--message-bg-hover); + gap:.04in; +} +.setting{ + background:var(--user-info-bg); + padding:.075in; + border-radius:.075in; + box-shadow:0in 0in .1in var(--message-bg-hover); +} +.settingsname{ + font-size:.25in; + font-weight:bold; + margin-right:.1in; +} +.flexspace{ + gap:.1in; +} +.titlediv{ + height:100%; + display: flex; + flex-direction: column; +} +.settingstitle{ + font-weight:900; + font-size:.25in; + border-bottom:solid var(--message-bg-hover); + background: var(--primary-bg); + padding: .02in .1in; +} +.exitsettings{ + position:absolute; + top:.05in; + right:.05in; + background:var(--channel-hover); + width:.3in; + height:.3in; + display:flex; + border-radius:1in; + justify-content: space-evenly; + align-items: center; + font-size:.2in; + cursor:pointer; + border:solid .04in black; +} + +.tritoggle{ + display:inline-block; + input{ + height:.15in; + width:.15in; + margin:.015in; + } + :first-child{ + accent-color:green; + } + :last-child{ + accent-color:red; + } +} + +.channelflex{ + flex-shrink:0; + flex-grow:0; + width:2.5in; + display: flex; + justify-content: space-evenly; + align-content: stretch; + flex-direction: column; + overflow: hidden; +} +.messageflex{ + display:flex; + justify-content: space-between; + width: 100%; +} +.userflex{ + display:flex; + flex-direction: column; + justify-content: center; +} +.savediv{ + position:absolute; + background:var(--message-bg-hover); + border:solid black; + border-radius:.075in; + padding:.05in .2in; + display:flex; + align-items: center; + right:50%; + transform:translate(50%,0); + bottom:.1in; + font-weight:bold; + font-size:.2in; + width:5in; + height:.5in; + button{ + background:green; + } +} \ No newline at end of file diff --git a/webpage/user.ts b/webpage/user.ts index 530b9c7..dadf121 100644 --- a/webpage/user.ts +++ b/webpage/user.ts @@ -4,6 +4,7 @@ import {markdown} from "./markdown.js"; import {Contextmenu} from "./contextmenu.js"; import {Localuser} from "./localuser.js"; import {Guild} from "./guild.js"; + class User{ static userids={}; owner:Localuser; @@ -15,6 +16,19 @@ class User{ discriminator:string; pronouns:string; bot:boolean; + static contextmenu:Contextmenu=new Contextmenu("User Menu"); + static setUpContextMenu(){ + this.contextmenu.addbutton("Copy user id",function(){ + navigator.clipboard.writeText(this.id); + }); + this.contextmenu.addbutton("Message user",function(){ + fetch(this.info.api.toString()+"/v9/users/@me/channels", + {method:"POST", + body:JSON.stringify({"recipients":[this.id]}), + headers: this.headers + }); + }) + } static checkuser(userjson,owner:Localuser){ if(User.userids[userjson.id]){ return User.userids[userjson.id]; @@ -58,6 +72,23 @@ class User{ this.changepfp(json.avatar); } } + bind(html:HTMLElement,guild:Guild=null){ + if(guild&&guild.id!=="@me"){ + Member.resolve(this,guild).then(_=>{ + _.bind(html); + }).catch(_=>{ + console.log(_) + }); + } + this.profileclick(html); + User.contextmenu.bind(html,this); + } + static async resolve(id:string,localuser:Localuser){ + const json=await fetch(localuser.info.api.toString()+"/v9/users/"+id+"/profile", + {headers:localuser.headers} + ).then(_=>_.json()); + return new User(json,localuser); + } changepfp(update:string){ this.avatar=update; this.hypotheticalpfp=false; @@ -140,4 +171,5 @@ class User{ } } } +User.setUpContextMenu(); export {User};