diff --git a/.dist/channel.js b/.dist/channel.js index 413c829..38410c1 100644 --- a/.dist/channel.js +++ b/.dist/channel.js @@ -404,10 +404,24 @@ class Channel { headers: this.headers }); } + async getmessage(id) { + if (this.messageids[id]) { + return this.messageids[id]; + } + else { + const gety = await fetch(this.info.api.toString() + "/v9/channels/" + this.id + "/messages?limit=1&around=" + id, { headers: this.headers }); + const json = await gety.json(); + return new Message(json[0], this); + } + } async getHTML() { if (this.guild !== this.localuser.lookingguild) { this.guild.loadGuild(); } + if (this.localuser.channelfocus && this.localuser.channelfocus.myhtml) { + this.localuser.channelfocus.myhtml.classList.remove("viewChannel"); + } + this.myhtml.classList.add("viewChannel"); this.guild.prevchannel = this; this.localuser.channelfocus = this; const prom = Message.wipeChanel(); @@ -420,7 +434,7 @@ class Channel { document.getElementById("typebox").disabled = !this.canMessage; } async putmessages() { - if (this.messages.length >= 100) { + if (this.messages.length >= 100 || this.allthewayup) { return; } ; @@ -429,6 +443,9 @@ class Channel { headers: this.headers, }); const responce = await j.json(); + if (responce.length !== 100) { + this.allthewayup = true; + } for (const thing of responce) { const messager = new Message(thing, this); if (this.messageids[messager.id] === undefined) { diff --git a/.dist/file.js b/.dist/file.js new file mode 100644 index 0000000..04075fe --- /dev/null +++ b/.dist/file.js @@ -0,0 +1,127 @@ +import { Fullscreen } from "./fullscreen.js"; +class File { + owner; + id; + filename; + content_type; + width; + height; + proxy_url; + url; + size; + constructor(fileJSON, owner) { + console.log(fileJSON); + this.owner = owner; + this.id = fileJSON.id; + this.filename = fileJSON.filename; + this.content_type = fileJSON.content_type; + this.width = fileJSON.width; + this.height = fileJSON.height; + this.url = fileJSON.url; + this.proxy_url = fileJSON.proxy_url; + this.content_type = fileJSON.content_type; + this.size = fileJSON.size; + } + getHTML(temp = false) { + const src = this.proxy_url || this.url; + if (this.content_type.startsWith('image/')) { + const img = document.createElement("img"); + img.classList.add("messageimg"); + img.onclick = function () { + const full = new Fullscreen(["img", img.src, ["fit"]]); + full.show(); + }; + img.src = src; + img.height = this.height; + img.width = this.width; + return img; + } + else if (this.content_type.startsWith('video/')) { + const video = document.createElement("video"); + const source = document.createElement("source"); + source.src = src; + video.append(source); + source.type = this.content_type; + video.controls = !temp; + return video; + } + else if (this.content_type.startsWith('audio/')) { + const audio = document.createElement("audio"); + const source = document.createElement("source"); + source.src = src; + audio.append(source); + source.type = this.content_type; + audio.controls = !temp; + return audio; + } + else { + return this.createunknown(); + } + } + upHTML(files, file) { + const div = document.createElement("div"); + const contained = this.getHTML(true); + div.classList.add("containedFile"); + div.append(contained); + const controls = document.createElement("div"); + const garbage = document.createElement("button"); + garbage.textContent = "🗑"; + garbage.onclick = _ => { + div.remove(); + files.splice(files.indexOf(file), 1); + }; + controls.classList.add("controls"); + div.append(controls); + controls.append(garbage); + return div; + } + static initFromBlob(file) { + return new File({ + filename: file.name, + size: file.size, + id: null, + content_type: file.type, + width: undefined, + height: undefined, + url: URL.createObjectURL(file), + proxy_url: undefined + }, null); + } + createunknown() { + console.log("🗎"); + const src = this.proxy_url || this.url; + const div = document.createElement("table"); + div.classList.add("unknownfile"); + const nametr = document.createElement("tr"); + div.append(nametr); + const fileicon = document.createElement("td"); + nametr.append(fileicon); + fileicon.append("🗎"); + fileicon.classList.add("fileicon"); + fileicon.rowSpan = 2; + const nametd = document.createElement("td"); + if (src) { + const a = document.createElement("a"); + a.href = src; + a.textContent = this.filename; + nametd.append(a); + } + else { + nametd.textContent = this.filename; + } + nametd.classList.add("filename"); + nametr.append(nametd); + const sizetr = document.createElement("tr"); + const size = document.createElement("td"); + sizetr.append(size); + size.textContent = "Size:" + File.filesizehuman(this.size); + size.classList.add("filesize"); + div.appendChild(sizetr); + return div; + } + static filesizehuman(fsize) { + var i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024)); + return +((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + ' ' + ['Bytes', 'Kilobytes', 'Megabytes', 'Gigabytes', 'Terabytes'][i]; + } +} +export { File }; diff --git a/.dist/index.js b/.dist/index.js index 1b98373..4f3b858 100644 --- a/.dist/index.js +++ b/.dist/index.js @@ -208,15 +208,15 @@ function filetohtml(file) { return createunknownfile(file); } } +import { File } from "./file.js"; document.addEventListener('paste', async (e) => { - Array.from(e.clipboardData.files).forEach(async (file) => { + Array.from(e.clipboardData.files).forEach(async (f) => { + const file = File.initFromBlob(f); e.preventDefault(); - const html = filetohtml(file); + const html = file.upHTML(images, f); pasteimage.appendChild(html); - const blob = URL.createObjectURL(file); - images.push(file); + images.push(f); imageshtml.push(html); - console.log(file.type); }); }); setTheme(); diff --git a/.dist/localuser.js b/.dist/localuser.js index 5f854cb..ea9751c 100644 --- a/.dist/localuser.js +++ b/.dist/localuser.js @@ -66,7 +66,11 @@ class Localuser { this.guildids[thing.guild_id].notisetting(thing); } for (const thing of ready.d.read_state.entries) { - const guild = this.resolveChannelFromID(thing.id).guild; + const channel = this.resolveChannelFromID(thing.id); + if (!channel) { + continue; + } + const guild = channel.guild; if (guild === undefined) { continue; } @@ -238,9 +242,11 @@ class Localuser { return; } resolveChannelFromID(ID) { - let resolve = this.guilds.find(guild => guild.channelids[ID]).channelids[ID]; - resolve ??= undefined; - return resolve; + let resolve = this.guilds.find(guild => guild.channelids[ID]); + if (resolve) { + return resolve.channelids[ID]; + } + return undefined; } updateChannel(JSON) { this.guildids[JSON.guild_id].updateChannel(JSON); @@ -264,12 +270,12 @@ class Localuser { } init() { const location = window.location.href.split("/"); + this.buildservers(); if (location[3] === "channels") { const guild = this.loadGuild(location[4]); guild.loadChannel(location[5]); this.channelfocus = guild.channelids[location[5]]; } - this.buildservers(); } loaduser() { document.getElementById("username").textContent = this.user.username; @@ -284,6 +290,12 @@ class Localuser { if (!guild) { guild = this.guildids["@me"]; } + if (this.lookingguild) { + this.lookingguild.html.classList.remove("serveropen"); + } + if (guild.html) { + guild.html.classList.add("serveropen"); + } this.lookingguild = guild; document.getElementById("serverName").textContent = guild.properties.name; //console.log(this.guildids,id) @@ -293,11 +305,18 @@ class Localuser { } buildservers() { const serverlist = document.getElementById("servers"); // + const outdiv = document.createElement("div"); const div = document.createElement("div"); div.textContent = "⌂"; div.classList.add("home", "servericon"); div["all"] = this.guildids["@me"]; - serverlist.appendChild(div); + this.guildids["@me"].html = outdiv; + const unread = document.createElement("div"); + unread.classList.add("unread"); + outdiv.append(unread); + outdiv.appendChild(div); + outdiv.classList.add("servernoti"); + serverlist.append(outdiv); div.onclick = function () { this["all"].loadGuild(); this["all"].loadChannel(); diff --git a/.dist/message.js b/.dist/message.js index 73bbe6b..19aef46 100644 --- a/.dist/message.js +++ b/.dist/message.js @@ -3,7 +3,7 @@ import { User } from "./user.js"; import { Member } from "./member.js"; import { markdown } from "./markdown.js"; import { Embed } from "./embed.js"; -import { Fullscreen } from "./fullscreen.js"; +import { File } from "./file.js"; class Message { static contextmenu = new Contextmenu("message menu"); owner; @@ -67,6 +67,13 @@ class Message { this.owner = owner; this.headers = this.owner.headers; for (const thing of Object.keys(messagejson)) { + if (thing === "attachments") { + this.attachments = []; + for (const thing of messagejson.attachments) { + this.attachments.push(new File(thing, this)); + } + continue; + } this[thing] = messagejson[thing]; } for (const thing in this.embeds) { @@ -195,9 +202,9 @@ class Message { line2.classList.add("reply"); line.classList.add("startreply"); replyline.classList.add("replyflex"); - fetch(this.info.api.toString() + "/v9/channels/" + this.message_reference.channel_id + "/messages?limit=1&around=" + this.message_reference.message_id, { headers: this.headers }).then(responce => responce.json()).then(responce => { - const author = new User(responce[0].author, this.localuser); - reply.appendChild(markdown(responce[0].content, { stdsize: true })); + this.channel.getmessage(this.message_reference.message_id).then(message => { + const author = message.author; + reply.appendChild(markdown(message.content, { stdsize: true })); minipfp.src = author.getpfpsrc(); author.profileclick(minipfp); username.textContent = author.username; @@ -277,24 +284,7 @@ class Message { console.log(this.attachments); const attatch = document.createElement("tr"); for (const thing of this.attachments) { - const array = thing.url.split("/"); - array.shift(); - array.shift(); - array.shift(); - const src = this.info.cdn.toString() + array.join("/"); - if (thing.content_type.startsWith('image/')) { - const img = document.createElement("img"); - img.classList.add("messageimg"); - img.onclick = function () { - const full = new Fullscreen(["img", img.src, ["fit"]]); - full.show(); - }; - img.src = src; - attatch.appendChild(img); - } - else { - attatch.appendChild(this.createunknown(thing.filename, thing.size, src)); - } + attatch.appendChild(thing.getHTML()); } messagedwrap.appendChild(attatch); } diff --git a/webpage/channel.ts b/webpage/channel.ts index 86e742b..6b4c546 100644 --- a/webpage/channel.ts +++ b/webpage/channel.ts @@ -412,10 +412,23 @@ class Channel{ headers:this.headers }) } + async getmessage(id:string):Promise{ + if(this.messageids[id]){ + return this.messageids[id]; + }else{ + const gety=await fetch(this.info.api.toString()+"/v9/channels/"+this.id+"/messages?limit=1&around="+id,{headers:this.headers}) + const json=await gety.json(); + return new Message(json[0],this); + } + } async getHTML(){ if(this.guild!==this.localuser.lookingguild){ this.guild.loadGuild(); } + if(this.localuser.channelfocus&&this.localuser.channelfocus.myhtml){ + this.localuser.channelfocus.myhtml.classList.remove("viewChannel"); + } + this.myhtml.classList.add("viewChannel") this.guild.prevchannel=this; this.localuser.channelfocus=this; const prom=Message.wipeChanel(); @@ -428,12 +441,15 @@ class Channel{ (document.getElementById("typebox") as HTMLInputElement).disabled=!this.canMessage; } async putmessages(){ - if(this.messages.length>=100){return}; + if(this.messages.length>=100||this.allthewayup){return}; const j=await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages?limit=100",{ method: 'GET', headers: this.headers, }) const responce=await j.json(); + if(responce.length!==100){ + this.allthewayup=true; + } for(const thing of responce){ const messager=new Message(thing,this) if(this.messageids[messager.id]===undefined){ diff --git a/webpage/file.ts b/webpage/file.ts new file mode 100644 index 0000000..cb83dd0 --- /dev/null +++ b/webpage/file.ts @@ -0,0 +1,126 @@ +import { Message } from "./message.js"; +import { Fullscreen } from "./fullscreen.js"; +type filejson= {id:string,filename:string,content_type:string,width:number,height:number,proxy_url:string|undefined,url:string,size:number}; +class File{ + owner:Message; + id:string; + filename:string; + content_type:string; + width:number; + height:number; + proxy_url:string; + url:string; + size:number; + constructor(fileJSON:filejson,owner:Message){ + console.log(fileJSON); + this.owner=owner; + this.id=fileJSON.id; + this.filename=fileJSON.filename; + this.content_type=fileJSON.content_type; + this.width=fileJSON.width; + this.height=fileJSON.height; + this.url=fileJSON.url; + this.proxy_url=fileJSON.proxy_url; + this.content_type=fileJSON.content_type; + this.size=fileJSON.size; + } + getHTML(temp:boolean=false):HTMLElement{ + const src=this.proxy_url||this.url; + if(this.content_type.startsWith('image/')){ + const img=document.createElement("img"); + img.classList.add("messageimg"); + img.onclick=function(){ + const full=new Fullscreen(["img",img.src,["fit"]]); + full.show(); + } + img.src=src; + img.height=this.height; + img.width=this.width; + return img; + }else if(this.content_type.startsWith('video/')){ + const video=document.createElement("video"); + const source=document.createElement("source"); + source.src=src; + video.append(source); + source.type=this.content_type; + video.controls=!temp; + return video; + }else if(this.content_type.startsWith('audio/')){ + const audio=document.createElement("audio"); + const source=document.createElement("source"); + source.src=src; + audio.append(source); + source.type=this.content_type; + audio.controls=!temp; + return audio; + }else{ + return this.createunknown(); + } + } + upHTML(files:Blob[],file:globalThis.File):HTMLElement{ + const div=document.createElement("div"); + const contained=this.getHTML(true); + div.classList.add("containedFile"); + div.append(contained); + const controls=document.createElement("div"); + const garbage=document.createElement("button"); + garbage.textContent="🗑"; + garbage.onclick=_=>{ + div.remove(); + files.splice(files.indexOf(file),1); + } + controls.classList.add("controls"); + div.append(controls); + controls.append(garbage); + return div; + } + static initFromBlob(file:globalThis.File){ + return new File({ + filename:file.name, + size:file.size, + id:null, + content_type:file.type, + width:undefined, + height:undefined, + url:URL.createObjectURL(file), + proxy_url:undefined + },null) + } + createunknown():HTMLElement{ + console.log("🗎") + const src=this.proxy_url||this.url; + const div=document.createElement("table"); + div.classList.add("unknownfile"); + const nametr=document.createElement("tr"); + div.append(nametr); + const fileicon=document.createElement("td"); + nametr.append(fileicon); + fileicon.append("🗎"); + fileicon.classList.add("fileicon"); + fileicon.rowSpan=2; + const nametd=document.createElement("td"); + if(src){ + const a=document.createElement("a"); + a.href=src; + a.textContent=this.filename; + nametd.append(a); + }else{ + nametd.textContent=this.filename; + } + + nametd.classList.add("filename"); + nametr.append(nametd); + const sizetr=document.createElement("tr"); + const size=document.createElement("td"); + sizetr.append(size); + size.textContent="Size:"+File.filesizehuman(this.size); + size.classList.add("filesize"); + div.appendChild(sizetr); + return div; + } + static filesizehuman(fsize:number){ + var i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024)); + return +((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + ' ' + ['Bytes', 'Kilobytes', 'Megabytes', 'Gigabytes', 'Terabytes'][i]; + } +} +export{File} diff --git a/webpage/guild.ts b/webpage/guild.ts index ff92329..1db660c 100644 --- a/webpage/guild.ts +++ b/webpage/guild.ts @@ -20,7 +20,7 @@ class Guild{ position:number; parent_id:string; member:Member; - html:HTMLUnknownElement; + html:HTMLElement; static contextmenu=new Contextmenu("guild menu"); static setupcontextmenu(){ Guild.contextmenu.addbutton("Copy Guild id",function(){ diff --git a/webpage/index.html b/webpage/index.html index 02b72d3..2dab8f6 100644 --- a/webpage/index.html +++ b/webpage/index.html @@ -10,27 +10,6 @@ -

Jank Client is loading

This shouldn't take long

diff --git a/webpage/index.ts b/webpage/index.ts index 996392d..20ea565 100644 --- a/webpage/index.ts +++ b/webpage/index.ts @@ -189,7 +189,7 @@ function getguildinfo(){ } -const images=[]; +const images:Blob[]=[]; const imageshtml=[]; function createunknown(fname,fsize){ const div=document.createElement("table"); @@ -235,17 +235,16 @@ function filetohtml(file){ return createunknownfile(file); } } +import { File } from "./file.js"; document.addEventListener('paste', async (e) => { - Array.from(e.clipboardData.files).forEach(async (file) => { - e.preventDefault(); - const html=filetohtml(file); - pasteimage.appendChild(html); - const blob = URL.createObjectURL(file); - images.push(file) - imageshtml.push(html); - - console.log(file.type) - }); + Array.from(e.clipboardData.files).forEach(async (f) => { + const file=File.initFromBlob(f); + e.preventDefault(); + const html=file.upHTML(images,f); + pasteimage.appendChild(html); + images.push(f) + imageshtml.push(html); + }); }); setTheme(); diff --git a/webpage/localuser.ts b/webpage/localuser.ts index cf09acf..31e5b27 100644 --- a/webpage/localuser.ts +++ b/webpage/localuser.ts @@ -72,7 +72,9 @@ class Localuser{ } for(const thing of ready.d.read_state.entries){ - const guild=this.resolveChannelFromID(thing.id).guild; + const channel=this.resolveChannelFromID(thing.id); + if(!channel){continue;} + const guild=channel.guild; if(guild===undefined){ continue } @@ -246,9 +248,11 @@ class Localuser{ return; } resolveChannelFromID(ID:string):Channel{ - let resolve=this.guilds.find(guild => guild.channelids[ID]).channelids[ID]; - resolve??=undefined; - return resolve; + let resolve=this.guilds.find(guild => guild.channelids[ID]); + if(resolve){ + return resolve.channelids[ID]; + } + return undefined; } updateChannel(JSON):void{ this.guildids[JSON.guild_id].updateChannel(JSON); @@ -273,12 +277,13 @@ class Localuser{ } init():void{ const location=window.location.href.split("/"); + this.buildservers(); if(location[3]==="channels"){ const guild=this.loadGuild(location[4]); guild.loadChannel(location[5]); this.channelfocus=guild.channelids[location[5]]; } - this.buildservers(); + } loaduser():void{ document.getElementById("username").textContent=this.user.username; @@ -293,6 +298,12 @@ class Localuser{ if(!guild){ guild=this.guildids["@me"]; } + if(this.lookingguild){ + this.lookingguild.html.classList.remove("serveropen"); + } + if(guild.html){ + guild.html.classList.add("serveropen") + } this.lookingguild=guild; document.getElementById("serverName").textContent=guild.properties.name; //console.log(this.guildids,id) @@ -302,12 +313,20 @@ class Localuser{ } buildservers():void{ const serverlist=document.getElementById("servers");// - + const outdiv=document.createElement("div"); const div=document.createElement("div"); + div.textContent="⌂"; div.classList.add("home","servericon") div["all"]=this.guildids["@me"]; - serverlist.appendChild(div) + this.guildids["@me"].html=outdiv; + const unread=document.createElement("div"); + unread.classList.add("unread"); + outdiv.append(unread); + outdiv.appendChild(div); + + outdiv.classList.add("servernoti") + serverlist.append(outdiv); div.onclick=function(){ this["all"].loadGuild(); this["all"].loadChannel(); diff --git a/webpage/message.ts b/webpage/message.ts index 1df1456..10d6d3a 100644 --- a/webpage/message.ts +++ b/webpage/message.ts @@ -7,6 +7,7 @@ import {Fullscreen} from "./fullscreen.js"; import { Channel } from "./channel.js"; import {Localuser} from "./localuser.js"; import { Role } from "./role.js"; +import {File} from "./file.js"; class Message{ static contextmenu=new Contextmenu("message menu"); @@ -16,7 +17,7 @@ class Message{ author:User; mentions:User[]; mention_roles:Role[]; - attachments;//probably should be its own class tbh, should be Attachments[] + attachments:File[];//probably should be its own class tbh, should be Attachments[] id:string; message_reference; type:number; @@ -72,6 +73,13 @@ class Message{ this.owner=owner; this.headers=this.owner.headers; for(const thing of Object.keys(messagejson)){ + if(thing==="attachments"){ + this.attachments=[]; + for(const thing of messagejson.attachments){ + this.attachments.push(new File(thing,this)); + } + continue; + } this[thing]=messagejson[thing]; } for(const thing in this.embeds){ @@ -199,11 +207,9 @@ class Message{ line2.classList.add("reply"); line.classList.add("startreply"); replyline.classList.add("replyflex") - fetch(this.info.api.toString()+"/v9/channels/"+this.message_reference.channel_id+"/messages?limit=1&around="+this.message_reference.message_id,{headers:this.headers}).then(responce=>responce.json()).then(responce=>{ - const author=new User(responce[0].author,this.localuser); - - reply.appendChild(markdown(responce[0].content,{stdsize:true})); - + this.channel.getmessage(this.message_reference.message_id).then(message=>{ + const author=message.author; + reply.appendChild(markdown(message.content,{stdsize:true})); minipfp.src=author.getpfpsrc() author.profileclick(minipfp) username.textContent=author.username; @@ -285,21 +291,7 @@ class Message{ console.log(this.attachments) const attatch = document.createElement("tr") for(const thing of this.attachments){ - const array=thing.url.split("/");array.shift();array.shift();array.shift(); - const src=this.info.cdn.toString()+array.join("/"); - if(thing.content_type.startsWith('image/')){ - const img=document.createElement("img"); - img.classList.add("messageimg") - img.onclick=function(){ - const full=new Fullscreen(["img",img.src,["fit"]]); - full.show(); - } - img.src=src; - attatch.appendChild(img) - }else{ - attatch.appendChild(this.createunknown(thing.filename,thing.size,src)) - } - + attatch.appendChild(thing.getHTML()) } messagedwrap.appendChild(attatch) } diff --git a/webpage/style.css b/webpage/style.css index 2f856bb..b8fa005 100644 --- a/webpage/style.css +++ b/webpage/style.css @@ -8,6 +8,10 @@ body { margin: 0; padding: 0; } +video{ + max-width: 3in; + max-height: 4in; +} .collapse{ width:0px !important; overflow: hidden; @@ -152,11 +156,14 @@ h2 { .servericon { transition: border-radius .2s; position: relative; + margin: .0in 0in 0.03in 0; } .servericon:hover { border-radius: 30%; } - +.serveropen .servericon{ + border-radius: 30%; +} .contextbutton:hover { background-color: var(--primary-bg); } @@ -177,6 +184,7 @@ h2 { vertical-align: top; height: 100dvh; overflow-x: hidden; + padding: 0.02in .05in 0.0in .05in; } #servers::-webkit-scrollbar { @@ -556,8 +564,12 @@ textarea { .channel { user-select: none; cursor: pointer; + transition: font-weight .1s; +} +.viewChannel{ + font-weight:900; + background: color-mix(in srgb, var(--channel-hover) 60%, transparent) } - #servername { margin-top: .1in; margin-bottom: .1in; @@ -845,17 +857,24 @@ span { background-color: var(--primary-text); height: .075in; width: .075in; - transition: transform .2s, background .2s, height .2s, width .2s; - transform: translate(-.20in, .2in); + transition: transform .2s, background .2s, height .3s, width .2s; + transform: translate(-.14in, .2in); z-index: 10; - border-radius: 50%; + border-radius: .2in; border: solid; border-width: .02in; border-color: var(--black); } - +.servernoti:hover .unread{ + transform: translate(-.1in, 0.15in); + height:.2in; +} +.serveropen .unread{ + transform: translate(-.1in, 0.1in) !important; + height:.3in !important; +} .notiunread { - transform: translate(0, .2in); + transform: translate(-.1in, .2in); } .pinged { @@ -1025,3 +1044,13 @@ span { overflow: hidden; max-width: 100%; } +.controls{ + position:absolute; + top:0px; + right:0px; +} +.containedFile{ + position:relative !important; + width: fit-content; + box-shadow:.02in .02in .05in black; +}