diff --git a/src/webpage/channel.ts b/src/webpage/channel.ts index 01dab52..b798ed6 100644 --- a/src/webpage/channel.ts +++ b/src/webpage/channel.ts @@ -2,11 +2,10 @@ import{ Message }from"./message.js"; import{ AVoice }from"./audio.js"; import{ Contextmenu }from"./contextmenu.js"; -import{ Dialog }from"./dialog.js"; import{ Guild }from"./guild.js"; import{ Localuser }from"./localuser.js"; import{ Permissions }from"./permissions.js"; -import{ Settings }from"./settings.js"; +import{ BDialog, Settings }from"./settings.js"; import{ Role, RoleList }from"./role.js"; import{ InfiniteScroller }from"./infiniteScroller.js"; import{ SnowFlake }from"./snowflake.js"; @@ -43,7 +42,7 @@ class Channel extends SnowFlake{ lastpin!: string; move_id?: string; typing!: number; - message_notifications!: number; + message_notifications:number=3; allthewayup!: boolean; static contextmenu = new Contextmenu("channel menu"); replyingto!: Message | null; @@ -53,6 +52,14 @@ class Channel extends SnowFlake{ messages: Map = new Map(); voice?:Voice; bitrate:number=128000; + + muted:boolean=false; + mute_config= {selected_time_window: -1,end_time: 0} + handleUserOverrides(settings:{message_notifications: number,muted: boolean,mute_config: {selected_time_window: number,end_time: number},channel_id: string}){ + this.message_notifications=settings.message_notifications; + this.muted=settings.muted; + this.mute_config=settings.mute_config; + } static setupcontextmenu(){ this.contextmenu.addbutton(()=>I18n.getTranslation("channel.copyId"), function(this: Channel){ navigator.clipboard.writeText(this.id); @@ -76,6 +83,12 @@ class Channel extends SnowFlake{ return this.isAdmin(); } ); + this.contextmenu.addbutton( + ()=>I18n.getTranslation("guild.notifications"), + function(){ + this.setnotifcation(); + } + ) this.contextmenu.addbutton( ()=>I18n.getTranslation("channel.makeInvite"), @@ -129,50 +142,21 @@ class Channel extends SnowFlake{ }); }; update(); - new Dialog([ - "vdiv", - ["title", I18n.getTranslation("inviteOptions.title")], - ["text", `to #${this.name} in ${this.guild.properties.name}`], - [ - "select", - "Expire after:", - [ - I18n.getTranslation("inviteOptions.30m"), - I18n.getTranslation("inviteOptions.1h"), - I18n.getTranslation("inviteOptions.6h"), - I18n.getTranslation("inviteOptions.12h"), - I18n.getTranslation("inviteOptions.1d"), - I18n.getTranslation("inviteOptions.7d"), - I18n.getTranslation("inviteOptions.30d"), - I18n.getTranslation("inviteOptions.never"), - ], - function(e: Event){ - expires = [1800, 3600, 21600, 43200, 86400, 604800, 2592000, 0,][(e.srcElement as HTMLSelectElement).selectedIndex]; + const inviteOptions=new BDialog("",{noSubmit:true}); + inviteOptions.options.addTitle(I18n.getTranslation("inviteOptions.title")); + inviteOptions.options.addText(I18n.getTranslation("invite.subtext",this.name,this.guild.properties.name)); - update(); - }, - 0, - ], - [ - "select", - "Max uses:", - [ - I18n.getTranslation("inviteOptions.noLimit"), - I18n.getTranslation("inviteOptions.limit","1"), - I18n.getTranslation("inviteOptions.limit","5"), - I18n.getTranslation("inviteOptions.limit","10"), - I18n.getTranslation("inviteOptions.limit","25"), - I18n.getTranslation("inviteOptions.limit","50"), - I18n.getTranslation("inviteOptions.limit","100"), - ], - function(e: Event){ - uses = [0, 1, 5, 10, 25, 50, 100][(e.srcElement as HTMLSelectElement).selectedIndex]; - update(); - }, - 0, - ], - ["html", div], - ]).show(); + inviteOptions.options.addSelect(I18n.getTranslation("invite.expireAfter"),()=>{}, + ["30m","1h","6h","12h","1d","7d","30d","never"].map((e)=>I18n.getTranslation("inviteOptions."+e)) + ).onchange=(e)=>{expires=[1800, 3600, 21600, 43200, 86400, 604800, 2592000, 0][e];update()}; + + const timeOptions=["1","5","10","25","50","100"].map((e)=>I18n.getTranslation("inviteOptions.limit",e)) + timeOptions.unshift(I18n.getTranslation("inviteOptions.noLimit")) + inviteOptions.options.addSelect(I18n.getTranslation("invite.expireAfter"),()=>{},timeOptions) + .onchange=(e)=>{uses=[0, 1, 5, 10, 25, 50, 100][e];update()}; + + inviteOptions.options.addHTMLArea(div); + inviteOptions.show(); } generateSettings(){ this.sortPerms(); @@ -938,6 +922,81 @@ class Channel extends SnowFlake{ } } lastmessage: Message | undefined; + setnotifcation(){ + const defualt=I18n.getTranslation("guild."+["all", "onlyMentions", "none","default"][this.guild.message_notifications]) + const options=["all", "onlyMentions", "none","default"].map(e=>I18n.getTranslation("guild."+e,defualt)); + const notiselect=new BDialog(""); + const form=notiselect.options.addForm("",(_,sent:any)=>{ + notiselect.hide(); + console.log(sent); + this.message_notifications = sent.channel_overrides[this.id].message_notifications; + },{ + fetchURL:`${this.info.api}/users/@me/guilds/${this.guild.id}/settings/`, + method:"PATCH", + headers:this.headers + }); + form.addSelect(I18n.getTranslation("guild.selectnoti"),"message_notifications",options,{ + radio:true, + defaultIndex:this.message_notifications + },[0,1,2,3]); + + form.addPreprocessor((e:any)=>{ + const message_notifications=e.message_notifications; + delete e.message_notifications; + e.channel_overrides={ + [this.id]:{ + message_notifications, + muted:this.muted, + mute_config:this.mute_config, + channel_id:this.id + } + } + }) + /* + let noti = this.message_notifications; + const defualt=I18n.getTranslation("guild."+["all", "onlyMentions", "none","default"][this.guild.message_notifications]) + const options=["all", "onlyMentions", "none","default"].map(e=>I18n.getTranslation("guild."+e,defualt)) + const notiselect = new Dialog([ + "vdiv", + [ + "radio", + I18n.getTranslation("guild.selectnoti"), + options, + function(e: string){ + noti = options.indexOf(e); + }, + noti, + ], + [ + "button", + "", + "submit", + (_: any)=>{ + // + fetch(this.info.api + `/users/@me/guilds/${this.guild.id}/settings/`, { + method: "PATCH", + headers: this.headers, + body: JSON.stringify({ + channel_overrides:{ + [this.id]:{ + message_notifications: noti, + muted:false, + mute_config:{ + selected_time_window:0, + end_time:0 + }, + channel_id:this.id + } + } + }), + }).then(()=>notiselect.hide()); + this.message_notifications = noti; + }, + ], + ]); + */ + notiselect.show(); + } async putmessages(){ //TODO swap out with the WS op code if(this.allthewayup){ @@ -1229,16 +1288,17 @@ class Channel extends SnowFlake{ notinumber = null; } notinumber ??= this.guild.message_notifications; + console.warn("info:",notinumber); switch(Number(notinumber)){ - case 0: - return"all"; - case 1: - return"mentions"; - case 2: - return"none"; - case 3: - default: - return"default"; + case 0: + return"all"; + case 1: + return"mentions"; + case 2: + return"none"; + case 3: + default: + return"default"; } } async sendMessage( diff --git a/src/webpage/dialog.ts b/src/webpage/dialog.ts deleted file mode 100644 index fe7a2fd..0000000 --- a/src/webpage/dialog.ts +++ /dev/null @@ -1,273 +0,0 @@ -type dialogjson = -| ["hdiv", ...dialogjson[]] -| ["vdiv", ...dialogjson[]] -| ["img", string, [number, number] | undefined | ["fit"]] -| ["checkbox", string, boolean, (this: HTMLInputElement, e: Event) => unknown] -| ["button", string, string, (this: HTMLButtonElement, e: Event) => unknown] -| ["mdbox", string, string, (this: HTMLTextAreaElement, e: Event) => unknown] -| ["textbox", string, string, (this: HTMLInputElement, e: Event) => unknown] -| ["fileupload", string, (this: HTMLInputElement, e: Event) => unknown] -| ["text", string] -| ["title", string] -| ["radio", string, string[], (this: unknown, e: string) => unknown, number] -| ["html", HTMLElement] -| ["select", string, string[], (this: HTMLSelectElement, e: Event) => unknown, number] -| ["tabs", [string, dialogjson][]]; -class Dialog{ - layout: dialogjson; - onclose: Function; - onopen: Function; - html: HTMLDivElement; - background!: HTMLDivElement; - constructor( - layout: dialogjson, - onclose = (_: any)=>{}, - onopen = (_: any)=>{} - ){ - this.layout = layout; - this.onclose = onclose; - this.onopen = onopen; - const div = document.createElement("div"); - div.appendChild(this.tohtml(layout)); - this.html = div; - this.html.classList.add("centeritem"); - if(!(layout[0] === "img")){ - this.html.classList.add("nonimagecenter"); - } - } - tohtml(array: dialogjson): HTMLElement{ - switch(array[0]){ - case"img": - const img = document.createElement("img"); - img.src = array[1]; - if(array[2] != undefined){ - if(array[2].length === 2){ - img.width = array[2][0]; - img.height = array[2][1]; - }else if(array[2][0] === "fit"){ - img.classList.add("imgfit"); - } - } - return img; - case"hdiv": - const hdiv = document.createElement("div"); - hdiv.classList.add("flexltr"); - - for(const thing of array){ - if(thing === "hdiv"){ - continue; - } - hdiv.appendChild(this.tohtml(thing)); - } - return hdiv; - case"vdiv": - const vdiv = document.createElement("div"); - vdiv.classList.add("flexttb"); - for(const thing of array){ - if(thing === "vdiv"){ - continue; - } - vdiv.appendChild(this.tohtml(thing)); - } - return vdiv; - case"checkbox": { - const div = document.createElement("div"); - const checkbox = document.createElement("input"); - div.appendChild(checkbox); - const label = document.createElement("span"); - checkbox.checked = array[2]; - label.textContent = array[1]; - div.appendChild(label); - checkbox.addEventListener("change", array[3]); - checkbox.type = "checkbox"; - return div; - } - case"button": { - const div = document.createElement("div"); - const input = document.createElement("button"); - - const label = document.createElement("span"); - input.textContent = array[2]; - label.textContent = array[1]; - div.appendChild(label); - div.appendChild(input); - input.addEventListener("click", array[3]); - return div; - } - case"mdbox": { - const div = document.createElement("div"); - const input = document.createElement("textarea"); - input.value = array[2]; - const label = document.createElement("span"); - label.textContent = array[1]; - input.addEventListener("input", array[3]); - div.appendChild(label); - div.appendChild(document.createElement("br")); - div.appendChild(input); - return div; - } - case"textbox": { - const div = document.createElement("div"); - const input = document.createElement("input"); - input.value = array[2]; - input.type = "text"; - const label = document.createElement("span"); - label.textContent = array[1]; - console.log(array[3]); - input.addEventListener("input", array[3]); - div.appendChild(label); - div.appendChild(input); - return div; - } - case"fileupload": { - const div = document.createElement("div"); - const input = document.createElement("input"); - input.type = "file"; - const label = document.createElement("span"); - label.textContent = array[1]; - div.appendChild(label); - div.appendChild(input); - input.addEventListener("change", array[2]); - console.log(array); - return div; - } - case"text": { - const span = document.createElement("span"); - span.textContent = array[1]; - return span; - } - case"title": { - const span = document.createElement("span"); - span.classList.add("title"); - span.textContent = array[1]; - return span; - } - case"radio": { - const div = document.createElement("div"); - const fieldset = document.createElement("fieldset"); - fieldset.addEventListener("change", ()=>{ - let i = -1; - for(const thing of Array.from(fieldset.children)){ - i++; - if(i === 0){ - continue; - } - const checkbox = thing.children[0].children[0] as HTMLInputElement; - if(checkbox.checked){ - array[3](checkbox.value); - } - } - }); - const legend = document.createElement("legend"); - legend.textContent = array[1]; - fieldset.appendChild(legend); - let i = 0; - for(const thing of array[2]){ - const div = document.createElement("div"); - const input = document.createElement("input"); - input.classList.add("radio"); - input.type = "radio"; - input.name = array[1]; - input.value = thing; - if(i === array[4]){ - input.checked = true; - } - const label = document.createElement("label"); - - label.appendChild(input); - const span = document.createElement("span"); - span.textContent = thing; - label.appendChild(span); - div.appendChild(label); - fieldset.appendChild(div); - i++; - } - div.appendChild(fieldset); - return div; - } - case"html": - return array[1]; - - case"select": { - const div = document.createElement("div"); - const label = document.createElement("label"); - const selectSpan = document.createElement("span"); - selectSpan.classList.add("selectspan"); - const select = document.createElement("select"); - const selectArrow = document.createElement("span"); - selectArrow.classList.add("svgicon","svg-category","selectarrow"); - - label.textContent = array[1]; - selectSpan.append(select); - selectSpan.append(selectArrow); - div.append(label); - div.appendChild(selectSpan); - for(const thing of array[2]){ - const option = document.createElement("option"); - option.textContent = thing; - select.appendChild(option); - } - select.selectedIndex = array[4]; - select.addEventListener("change", array[3]); - return div; - } - case"tabs": { - const table = document.createElement("div"); - table.classList.add("flexttb"); - const tabs = document.createElement("div"); - tabs.classList.add("flexltr"); - tabs.classList.add("tabbed-head"); - table.appendChild(tabs); - const content = document.createElement("div"); - content.classList.add("tabbed-content"); - table.appendChild(content); - - let shown: HTMLElement | undefined; - for(const thing of array[1]){ - const button = document.createElement("button"); - button.textContent = thing[0]; - tabs.appendChild(button); - - const html = this.tohtml(thing[1]); - content.append(html); - if(!shown){ - shown = html; - }else{ - html.style.display = "none"; - } - button.addEventListener("click", _=>{ - if(shown){ - shown.style.display = "none"; - } - html.style.display = ""; - shown = html; - }); - } - return table; - } - default: - console.error( - "can't find element:" + array[0], - " full element:", - array - ); - return document.createElement("span"); - } - } - show(){ - this.onopen(); - console.log("fullscreen"); - this.background = document.createElement("div"); - this.background.classList.add("background"); - document.body.appendChild(this.background); - document.body.appendChild(this.html); - this.background.onclick = _=>{ - this.hide(); - }; - } - hide(){ - document.body.removeChild(this.background); - document.body.removeChild(this.html); - } -} -export{ Dialog }; diff --git a/src/webpage/disimg.ts b/src/webpage/disimg.ts new file mode 100644 index 0000000..a1d2a1d --- /dev/null +++ b/src/webpage/disimg.ts @@ -0,0 +1,37 @@ +class ImagesDisplay{ + images:string[]; + index=0; + constructor(srcs:string[],index=0){ + this.images=srcs; + this.index=index; + } + weakbg=new WeakRef(document.createElement("div")); + get background():HTMLElement|undefined{ + return this.weakbg.deref(); + } + set background(e:HTMLElement){ + this.weakbg=new WeakRef(e); + } + makeHTML():HTMLElement{ + //TODO this should be able to display more than one image at a time lol + const image= document.createElement("img"); + image.src=this.images[this.index]; + image.classList.add("imgfit","centeritem"); + return image; + } + show(){ + this.background = document.createElement("div"); + this.background.classList.add("background"); + this.background.appendChild(this.makeHTML()); + this.background.onclick = _=>{ + this.hide(); + }; + document.body.append(this.background); + } + hide(){ + if(this.background){ + this.background.remove(); + } + } +} +export{ImagesDisplay} diff --git a/src/webpage/embed.ts b/src/webpage/embed.ts index d2f8fe9..e84105d 100644 --- a/src/webpage/embed.ts +++ b/src/webpage/embed.ts @@ -1,10 +1,10 @@ -import{ Dialog }from"./dialog.js"; import{ Message }from"./message.js"; import{ MarkDown }from"./markdown.js"; import{ embedjson, invitejson }from"./jsontypes.js"; import{ getapiurls, getInstances }from"./login.js"; import{ Guild }from"./guild.js"; import { I18n } from "./i18n.js"; +import { ImagesDisplay } from "./disimg.js"; class Embed{ type: string; @@ -178,7 +178,7 @@ Url.pathname.split("/")[Url.pathname.split("/").length - 1]; const img = document.createElement("img"); img.classList.add("messageimg"); img.onclick = function(){ - const full = new Dialog(["img", img.src, ["fit"]]); + const full = new ImagesDisplay([img.src]); full.show(); }; img.src = this.json.thumbnail.proxy_url; @@ -214,7 +214,7 @@ Url.pathname.split("/")[Url.pathname.split("/").length - 1]; if(this.json.thumbnail){ img.classList.add("embedimg"); img.onclick = function(){ - const full = new Dialog(["img", img.src, ["fit"]]); + const full = new ImagesDisplay([img.src]); full.show(); }; img.src = this.json.thumbnail.proxy_url; @@ -392,7 +392,7 @@ guild as invitejson["guild"] & { info: { cdn: string } } }; }else{ img.onclick = async ()=>{ - const full = new Dialog(["img", img.src, ["fit"]]); + const full = new ImagesDisplay([img.src]); full.show(); }; } diff --git a/src/webpage/file.ts b/src/webpage/file.ts index 3a67853..25a6b34 100644 --- a/src/webpage/file.ts +++ b/src/webpage/file.ts @@ -1,6 +1,6 @@ import{ Message }from"./message.js"; -import{ Dialog }from"./dialog.js"; import{ filejson }from"./jsontypes.js"; +import { ImagesDisplay } from "./disimg.js"; class File{ owner: Message | null; @@ -40,7 +40,7 @@ class File{ img.classList.add("messageimg"); div.classList.add("messageimgdiv"); img.onclick = function(){ - const full = new Dialog(["img", img.src, ["fit"]]); + const full = new ImagesDisplay([img.src]); full.show(); }; img.src = src; diff --git a/src/webpage/guild.ts b/src/webpage/guild.ts index 79e7b7d..48118ef 100644 --- a/src/webpage/guild.ts +++ b/src/webpage/guild.ts @@ -2,9 +2,8 @@ import{ Channel }from"./channel.js"; import{ Localuser }from"./localuser.js"; import{ Contextmenu }from"./contextmenu.js"; import{ Role, RoleList }from"./role.js"; -import{ Dialog }from"./dialog.js"; import{ Member }from"./member.js"; -import{ Settings }from"./settings.js"; +import{ BDialog, Settings }from"./settings.js"; import{ Permissions }from"./permissions.js"; import{ SnowFlake }from"./snowflake.js"; import{channeljson,guildjson,emojijson,memberjson,invitejson,rolesjson,}from"./jsontypes.js"; @@ -238,7 +237,7 @@ class Guild extends SnowFlake{ this.localuser.perminfo.guilds[this.id] = e; } notisetting(settings: { - channel_overrides?: unknown[]; + channel_overrides: {message_notifications: number,muted: boolean,mute_config: {selected_time_window: number,end_time: number},channel_id: string}[]; message_notifications: any; flags?: number; hide_muted_channels?: boolean; @@ -253,66 +252,42 @@ class Guild extends SnowFlake{ guild_id?: string; }){ this.message_notifications = settings.message_notifications; + for(const override of settings.channel_overrides){ + const channel=this.localuser.channelids.get(override.channel_id); + if(!channel) continue; + channel.handleUserOverrides(override); + } } setnotifcation(){ - let noti = this.message_notifications; - const options=["all", "onlyMentions", "none"].map(e=>I18n.getTranslation("guild."+e)) - const notiselect = new Dialog([ - "vdiv", - [ - "radio", - I18n.getTranslation("guild.selectnoti"), - options, - function(e: string){ - noti = options.indexOf(e); - }, - noti, - ], - [ - "button", - "", - "submit", - (_: any)=>{ - // - fetch(this.info.api + `/users/@me/guilds/${this.id}/settings/`, { - method: "PATCH", - headers: this.headers, - body: JSON.stringify({ - message_notifications: noti, - }), - }); - this.message_notifications = noti; - }, - ], - ]); + + const options=["all", "onlyMentions", "none"].map(e=>I18n.getTranslation("guild."+e)); + const notiselect=new BDialog(""); + const form=notiselect.options.addForm("",(_,sent:any)=>{ + notiselect.hide(); + this.message_notifications = sent.message_notifications; + },{ + fetchURL:`${this.info.api}/users/@me/guilds/${this.id}/settings/`, + method:"PATCH", + headers:this.headers + }); + form.addSelect(I18n.getTranslation("guild.selectnoti"),"message_notifications",options,{ + radio:true, + defaultIndex:this.message_notifications + },[0,1,2]); notiselect.show(); } confirmleave(){ - const full = new Dialog([ - "vdiv", - ["title", I18n.getTranslation("guild.confirmLeave")], - [ - "hdiv", - [ - "button", - "", - I18n.getTranslation("guild.yesLeave"), - (_: any)=>{ - this.leave().then(_=>{ - full.hide(); - }); - }, - ], - [ - "button", - "", - I18n.getTranslation("guild.noLeave"), - (_: any)=>{ - full.hide(); - }, - ], - ], - ]); + const full = new BDialog(""); + full.options.addTitle(I18n.getTranslation("guild.confirmLeave")) + const options=full.options.addOptions("",{ltr:true}); + options.addButtonInput("",I18n.getTranslation("guild.yesLeave"),()=>{ + this.leave().then(_=>{ + full.hide(); + }); + }); + options.addButtonInput("",I18n.getTranslation("guild.noLeave"),()=>{ + full.hide(); + }); full.show(); } async leave(){ @@ -458,46 +433,26 @@ class Guild extends SnowFlake{ } confirmDelete(){ let confirmname = ""; - const full = new Dialog([ - "vdiv", - [ - "title", - I18n.getTranslation("guild.confirmDelete",this.properties.name) - ], - [ - "textbox", - I18n.getTranslation("guild.serverName"), - "", - function(this: HTMLInputElement){ - confirmname = this.value; - }, - ], - [ - "hdiv", - [ - "button", - "", - I18n.getTranslation("guild.yesDelete"), - (_: any)=>{ - console.log(confirmname); - if(confirmname !== this.properties.name){ - return; - } - this.delete().then(_=>{ - full.hide(); - }); - }, - ], - [ - "button", - "", - I18n.getTranslation("guild.noDelete"), - (_: any)=>{ - full.hide(); - }, - ], - ], - ]); + + const full = new BDialog(""); + full.options.addTitle(I18n.getTranslation("guild.confirmDelete",this.properties.name)); + full.options.addTextInput(I18n.getTranslation("guild.serverName"),()=>{}).onchange=(e)=>confirmname=e; + + const options=full.options.addOptions("",{ltr:true}); + options.addButtonInput("",I18n.getTranslation("guild.yesDelete"),()=>{ + if(confirmname !== this.properties.name){ + //TODO maybe some sort of form error? idk + alert("names don't match"); + return; + } + this.delete().then(_=>{ + full.hide(); + }); + }); + + options.addButtonInput("",I18n.getTranslation("guild.noDelete"),()=>{ + full.hide(); + }); full.show(); } async delete(){ @@ -677,67 +632,27 @@ class Guild extends SnowFlake{ return thischannel; } createchannels(func = this.createChannel){ - let name = ""; - let category = 0; - const options=["voice", "text", "announcement"].map(e=>I18n.getTranslation("channel."+e)); - const numbers=[2,0,5] - const channelselect = new Dialog([ - "vdiv", - [ - "radio", - I18n.getTranslation("channel.selectType"), - options, - function(radio: string){ - console.log(radio); - category = numbers[options.indexOf(radio)] || 0; - }, - 1, - ], - [ - "textbox", - I18n.getTranslation("channel.selectName"), - "", - function(this: HTMLInputElement){ - name = this.value; - }, - ], - [ - "button", - "", - I18n.getTranslation("submit"), - ()=>{ - console.log(name, category); - func.bind(this)(name, category); - channelselect.hide(); - }, - ], - ]); + const options=["text", "announcement","voice"].map(e=>I18n.getTranslation("channel."+e)); + + const channelselect=new BDialog(""); + const form=channelselect.options.addForm("",(e:any)=>{ + func(e.name,e.type); + channelselect.hide(); + }); + + form.addSelect(I18n.getTranslation("channel.selectType"),"type",options,{radio:true},[0,5,2]); + form.addTextInput(I18n.getTranslation("channel.selectName"),"name"); channelselect.show(); } createcategory(){ - let name = ""; const category = 4; - const channelselect = new Dialog([ - "vdiv", - [ - "textbox", - I18n.getTranslation("channel.selectCatName"), - "", - function(this: HTMLInputElement){ - name = this.value; - }, - ], - [ - "button", - "", - I18n.getTranslation("submit"), - function(this:Guild){ - console.log(name, category); - this.createChannel(name, category); - channelselect.hide(); - }.bind(this), - ], - ]); + const channelselect=new BDialog(""); + const options=channelselect.options; + const form=options.addForm("",(e:any)=>{ + this.createChannel(e.name, category); + channelselect.hide(); + }); + form.addTextInput(I18n.getTranslation("channel.selectCatName"),"name"); channelselect.show(); } delChannel(json: channeljson){ diff --git a/src/webpage/jsontypes.ts b/src/webpage/jsontypes.ts index ae6134a..7a3d7a8 100644 --- a/src/webpage/jsontypes.ts +++ b/src/webpage/jsontypes.ts @@ -63,7 +63,7 @@ type readyjson = { }; user_guild_settings: { entries: { - channel_overrides: unknown[]; //will have to find example + channel_overrides: {message_notifications: number,muted: boolean,mute_config: {selected_time_window: number,end_time: number},channel_id: string}[]; message_notifications: number; flags: number; hide_muted_channels: boolean; @@ -523,6 +523,11 @@ roleCreate | { nickname: null }, s: number +}|{ + op: 0, + t: "PRESENCE_UPDATE", + d: presencejson, + s:number }; diff --git a/src/webpage/localuser.ts b/src/webpage/localuser.ts index 24c73d0..79bb009 100644 --- a/src/webpage/localuser.ts +++ b/src/webpage/localuser.ts @@ -3,11 +3,10 @@ import{ Channel }from"./channel.js"; import{ Direct }from"./direct.js"; import{ AVoice }from"./audio.js"; import{ User }from"./user.js"; -import{ Dialog }from"./dialog.js"; import{ getapiurls, getBulkInfo, setTheme, Specialuser, SW }from"./login.js"; import{channeljson,guildjson,mainuserjson,memberjson,memberlistupdatejson,messageCreateJson,presencejson,readyjson,startTypingjson,wsjson,}from"./jsontypes.js"; import{ Member }from"./member.js"; -import{ Form, FormError, Options, Settings }from"./settings.js"; +import{ BDialog, Form, FormError, Options, Settings }from"./settings.js"; import{ getTextNodeAtPosition, MarkDown }from"./markdown.js"; import { Bot } from "./bot.js"; import { Role } from "./role.js"; @@ -26,8 +25,6 @@ class Localuser{ initialized!: boolean; info!: Specialuser["serverurls"]; headers!: { "Content-type": string; Authorization: string }; - userConnections!: Dialog; - devPortal!: Dialog; ready!: readyjson; guilds!: Guild[]; guildids: Map = new Map(); @@ -559,6 +556,12 @@ class Localuser{ this.relationshipsUpdate(); break; } + case "PRESENCE_UPDATE":{ + if(temp.d.user){ + this.presences.set(temp.d.user.id, temp.d); + } + break; + } default :{ //@ts-ignore console.warn("Unhandled case "+temp.t,temp); @@ -888,99 +891,44 @@ class Localuser{ this.unreads(); } createGuild(){ - let inviteurl = ""; - const error = document.createElement("span"); - const fields: { name: string; icon: string | null } = { - name: "", - icon: null, - }; - const full = new Dialog([ - "tabs", - [ - [ - I18n.getTranslation("invite.joinUsing"), - [ - "vdiv", - [ - "textbox", - I18n.getTranslation("invite.inviteLinkCode"), - "", - function(this: HTMLInputElement){ - inviteurl = this.value; - }, - ], - ["html", error], - [ - "button", - "", - I18n.getTranslation("submit"), - (_: any)=>{ - let parsed = ""; - if(inviteurl.includes("/")){ - parsed = - inviteurl.split("/")[inviteurl.split("/").length - 1]; - }else{ - parsed = inviteurl; - } - fetch(this.info.api + "/invites/" + parsed, { - method: "POST", - headers: this.headers, - }) - .then(r=>r.json()) - .then(_=>{ - if(_.message){ - error.textContent = _.message; - } - }); - }, - ], - ], - ], - [ - I18n.getTranslation("guild.create"), - [ - "vdiv", - ["title", I18n.getTranslation("guild.create")], - [ - "fileupload", - I18n.getTranslation("guild.icon:"), - function(event: Event){ - const target = event.target as HTMLInputElement; - if(!target.files)return; - const reader = new FileReader(); - reader.readAsDataURL(target.files[0]); - reader.onload = ()=>{ - fields.icon = reader.result as string; - }; - }, - ], - [ - "textbox", - I18n.getTranslation("guild.name:"), - "", - function(this: HTMLInputElement, event: Event){ - const target = event.target as HTMLInputElement; - fields.name = target.value; - }, - ], - [ - "button", - "", - I18n.getTranslation("submit"), - ()=>{ - this.makeGuild(fields).then(_=>{ - if(_.message){ - alert(_.errors.name._errors[0].message); - }else{ - full.hide(); - } - }); - }, - ], - ], - ], - ], - ]); + + const full=new BDialog(""); + const buttons=full.options.addButtons("",{top:true}); + const viacode=buttons.add(I18n.getTranslation("invite.joinUsing")); + { + const form=viacode.addForm("",async (e: any)=>{ + let parsed = ""; + if(e.code.includes("/")){ + parsed = e.code.split("/")[e.code.split("/").length - 1]; + }else{ + parsed = e.code; + } + const json=await (await fetch(this.info.api + "/invites/" + parsed, { + method: "POST", + headers: this.headers, + })).json() + if(json.message){ + throw new FormError(text,json.message); + } + full.hide(); + }); + const text=form.addTextInput(I18n.getTranslation("invite.inviteLinkCode"),"code"); + } + const guildcreate=buttons.add(I18n.getTranslation("guild.create")); + { + const form=guildcreate.addForm("",(fields:any)=>{ + this.makeGuild(fields).then(_=>{ + if(_.message){ + alert(_.errors.name._errors[0].message); + }else{ + full.hide(); + } + }); + }); + form.addFileInput(I18n.getTranslation("guild.icon:"),"icon",{files:"one"}); + form.addTextInput(I18n.getTranslation("guild.name:"),"name",{required:true}); + + } full.show(); } async makeGuild(fields: { name: string; icon: string | null }){ @@ -996,7 +944,8 @@ class Localuser{ const content = document.createElement("div"); content.classList.add("flexttb","guildy"); content.textContent = I18n.getTranslation("guild.loadingDiscovery"); - const full = new Dialog(["html", content]); + const full = new BDialog(""); + full.options.addHTMLArea(content); full.show(); const res = await fetch(this.info.api + "/discoverable-guilds?limit=50", { @@ -2147,15 +2096,12 @@ class Localuser{ headers: this.headers, }); const json = await res.json(); - - const dialog = new Dialog([ - "vdiv", - ["title", I18n.getTranslation("instanceStats.name",this.instancePing.name) ], - ["text", I18n.getTranslation("instanceStats.users",json.counts.user)], - ["text", I18n.getTranslation("instanceStats.servers",json.counts.guild)], - ["text", I18n.getTranslation("instanceStats.messages",json.counts.message)], - ["text", I18n.getTranslation("instanceStats.members",json.counts.members)], - ]); + const dialog = new BDialog(""); + dialog.options.addTitle(I18n.getTranslation("instanceStats.name",this.instancePing.name)); + dialog.options.addText(I18n.getTranslation("instanceStats.users",json.counts.user)); + dialog.options.addText(I18n.getTranslation("instanceStats.servers",json.counts.guild)); + dialog.options.addText(I18n.getTranslation("instanceStats.messages",json.counts.message)); + dialog.options.addText(I18n.getTranslation("instanceStats.members",json.counts.members)); dialog.show(); } } diff --git a/src/webpage/login.ts b/src/webpage/login.ts index b79d819..3e578a2 100644 --- a/src/webpage/login.ts +++ b/src/webpage/login.ts @@ -1,5 +1,5 @@ -import{ Dialog }from"./dialog.js"; import { I18n } from "./i18n.js"; +import { BDialog, FormError } from "./settings.js"; const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); const iOS = /iPhone|iPad|iPod/i.test(navigator.userAgent); @@ -511,65 +511,43 @@ async function login(username: string, password: string, captcha: string){ capty.setAttribute("data-sitekey", response.captcha_sitekey); const script = document.createElement("script"); script.src = "https://js.hcaptcha.com/1/api.js"; - capt!.append(script); - capt!.append(capty); + capt!.append(script); + capt!.append(capty); } }else{ console.log(response); if(response.ticket){ - let onetimecode = ""; - new Dialog([ - "vdiv", - ["title", I18n.getTranslation("2faCode")], - [ - "textbox", - "", - "", - function(this: HTMLInputElement){ - // eslint-disable-next-line no-invalid-this - onetimecode = this.value; - }, - ], - [ - "button", - "", - I18n.getTranslation("submit"), - function(){ - fetch(api + "/auth/mfa/totp", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - code: onetimecode, - ticket: response.ticket, - }), - }) - .then(r=>r.json()) - .then(res=>{ - if(res.message){ - alert(res.message); - }else{ - console.warn(res); - if(!res.token)return; - adduser({ - serverurls: JSON.parse(localStorage.getItem("instanceinfo") as string), - email: username, - token: res.token, - }).username = username; - const redir = new URLSearchParams( - window.location.search - ).get("goback"); - if(redir){ - window.location.href = redir; - }else{ - window.location.href = "/channels/@me"; - } - } - }); - }, - ], - ]).show(); + const better=new BDialog(""); + const form=better.options.addForm("",(res:any)=>{ + if(res.message){ + throw new FormError(ti,res.message); + }else{ + console.warn(res); + if(!res.token)return; + adduser({ + serverurls: JSON.parse(localStorage.getItem("instanceinfo") as string), + email: username, + token: res.token, + }).username = username; + const redir = new URLSearchParams( + window.location.search + ).get("goback"); + if(redir){ + window.location.href = redir; + }else{ + window.location.href = "/channels/@me"; + } + } + },{ + fetchURL:api + "/auth/mfa/totp", + method:"POST", + headers:{ + "Content-Type": "application/json", + } + }); + form.addTitle(I18n.getTranslation("2faCode")); + const ti=form.addTextInput("","code"); + better.show() }else{ console.warn(response); if(!response.token)return; diff --git a/src/webpage/markdown.ts b/src/webpage/markdown.ts index 13f8167..6bddf49 100644 --- a/src/webpage/markdown.ts +++ b/src/webpage/markdown.ts @@ -1,10 +1,10 @@ import{ Channel }from"./channel.js"; -import{ Dialog }from"./dialog.js"; import{ Emoji }from"./emoji.js"; import{ Guild }from"./guild.js"; import { I18n } from "./i18n.js"; import{ Localuser }from"./localuser.js"; import{ Member }from"./member.js"; +import { BDialog } from "./settings.js"; class MarkDown{ txt: string[]; @@ -781,37 +781,20 @@ txt[j + 1] === undefined) if(this.trustedDomains.has(Url.host)){ open(); }else{ - const full: Dialog = new Dialog([ - "vdiv", - ["title", I18n.getTranslation("leaving")], - [ - "text", - I18n.getTranslation("goingToURL",Url.host) - ], - [ - "hdiv", - ["button", "", I18n.getTranslation("nevermind"), (_: any)=>full.hide()], - [ - "button", - "", - I18n.getTranslation("goThere"), - (_: any)=>{ - open(); - full.hide(); - }, - ], - [ - "button", - "", - I18n.getTranslation("goThereTrust"), - (_: any)=>{ - open(); - full.hide(); - this.trustedDomains.add(Url.host); - }, - ], - ], - ]); + const full=new BDialog(""); + full.options.addTitle(I18n.getTranslation("leaving")); + full.options.addText(I18n.getTranslation("goingToURL",Url.host)); + const options=full.options.addOptions("",{ltr:true}); + options.addButtonInput("",I18n.getTranslation("nevermind"),()=>full.hide()); + options.addButtonInput("",I18n.getTranslation("goThere"),()=>{ + open(); + full.hide(); + }); + options.addButtonInput("",I18n.getTranslation("goThereTrust"),()=>{ + open(); + full.hide(); + this.trustedDomains.add(Url.host); + }); full.show(); } }; diff --git a/src/webpage/member.ts b/src/webpage/member.ts index 3de6ed8..47ccbaa 100644 --- a/src/webpage/member.ts +++ b/src/webpage/member.ts @@ -3,8 +3,8 @@ import{ Role }from"./role.js"; import{ Guild }from"./guild.js"; import{ SnowFlake }from"./snowflake.js"; import{ memberjson, presencejson }from"./jsontypes.js"; -import{ Dialog }from"./dialog.js"; import { I18n } from "./i18n.js"; +import { BDialog } from "./settings.js"; class Member extends SnowFlake{ static already = {}; @@ -229,28 +229,13 @@ class Member extends SnowFlake{ return this.nick || this.user.username; } kick(){ - let reason = ""; - const menu = new Dialog([ - "vdiv", - ["title", I18n.getTranslation("member.kick",this.name,this.guild.properties.name)], - [ - "textbox", - I18n.getTranslation("member.reason:"), - "", - function(e: Event){ - reason = (e.target as HTMLInputElement).value; - }, - ], - [ - "button", - "", - I18n.getTranslation("submit"), - ()=>{ - this.kickAPI(reason); - menu.hide(); - }, - ], - ]); + const menu = new BDialog(""); + const form=menu.options.addForm("",((e:any)=>{ + this.kickAPI(e.reason); + menu.hide(); + })); + form.addTitle(I18n.getTranslation("member.kick",this.name,this.guild.properties.name)); + form.addTextInput(I18n.getTranslation("member.reason:"),"reason"); menu.show(); } kickAPI(reason: string){ @@ -262,28 +247,13 @@ class Member extends SnowFlake{ }); } ban(){ - let reason = ""; - const menu = new Dialog([ - "vdiv", - ["title", I18n.getTranslation("member.ban",this.name,this.guild.properties.name)], - [ - "textbox", - I18n.getTranslation("member.reason:",this.name,this.guild.properties.name), - "", - function(e: Event){ - reason = (e.target as HTMLInputElement).value; - }, - ], - [ - "button", - "", - I18n.getTranslation("submit",this.name,this.guild.properties.name), - ()=>{ - this.banAPI(reason); - menu.hide(); - }, - ], - ]); + const menu = new BDialog(""); + const form=menu.options.addForm("",((e:any)=>{ + this.banAPI(e.reason); + menu.hide(); + })); + form.addTitle(I18n.getTranslation("member.ban",this.name,this.guild.properties.name)); + form.addTextInput(I18n.getTranslation("member.reason:"),"reason"); menu.show(); } addRole(role:Role){ diff --git a/src/webpage/message.ts b/src/webpage/message.ts index cfac8b3..d8ba76f 100644 --- a/src/webpage/message.ts +++ b/src/webpage/message.ts @@ -10,10 +10,10 @@ import{ File }from"./file.js"; import{ SnowFlake }from"./snowflake.js"; import{ memberjson, messagejson }from"./jsontypes.js"; import{ Emoji }from"./emoji.js"; -import{ Dialog }from"./dialog.js"; import{ mobile }from"./login.js"; import { I18n } from "./i18n.js"; import { Hover } from "./hover.js"; +import { BDialog } from "./settings.js"; class Message extends SnowFlake{ static contextmenu = new Contextmenu("message menu"); @@ -87,7 +87,7 @@ class Message extends SnowFlake{ Message.contextmenu.addbutton( ()=>I18n.getTranslation("message.delete"), function(this: Message){ - this.delete(); + this.confirmDelete(); }, null, function(){ @@ -674,31 +674,7 @@ class Message extends SnowFlake{ this.delete(); return; } - const diaolog = new Dialog([ - "vdiv", - ["title", I18n.getTranslation("deleteConfirm")], - [ - "hdiv", - [ - "button", - "", - I18n.getTranslation("yes"), - ()=>{ - this.delete(); - diaolog.hide(); - }, - ], - [ - "button", - "", - I18n.getTranslation("no"), - ()=>{ - diaolog.hide(); - }, - ], - ] - ]); - diaolog.show(); + this.confirmDelete(); }; } if(buttons.childNodes.length !== 0){ @@ -714,6 +690,19 @@ class Message extends SnowFlake{ }; } } + confirmDelete(){ + const diaolog=new BDialog(""); + diaolog.options.addTitle(I18n.getTranslation("deleteConfirm")); + const options=diaolog.options.addOptions("",{ltr:true}); + options.addButtonInput("",I18n.getTranslation("yes"),()=>{ + this.delete(); + diaolog.hide(); + }); + options.addButtonInput("",I18n.getTranslation("no"),()=>{ + diaolog.hide(); + }) + diaolog.show(); + } updateReactions(){ const reactdiv = this.reactdiv.deref(); if(!reactdiv)return; diff --git a/src/webpage/settings.ts b/src/webpage/settings.ts index a4bae0c..e99d665 100644 --- a/src/webpage/settings.ts +++ b/src/webpage/settings.ts @@ -14,7 +14,9 @@ class Buttons implements OptionsElement{ buttonList!: HTMLDivElement; warndiv!: HTMLElement; value: unknown; - constructor(name: string){ + top=false; + constructor(name: string,{top=false}={}){ + this.top=top; this.buttons = []; this.name = name; } @@ -28,7 +30,7 @@ class Buttons implements OptionsElement{ generateHTML(){ const buttonList = document.createElement("div"); buttonList.classList.add("Buttons"); - buttonList.classList.add("flexltr"); + buttonList.classList.add(this.top?"flexttb":"flexltr"); this.buttonList = buttonList; const htmlarea = document.createElement("div"); htmlarea.classList.add("flexgrow"); @@ -43,6 +45,9 @@ class Buttons implements OptionsElement{ generateButtons(optionsArea:HTMLElement){ const buttonTable = document.createElement("div"); buttonTable.classList.add("settingbuttons"); + if(this.top){ + buttonTable.classList.add("flexltr"); + } for(const thing of this.buttons){ const button = document.createElement("button"); button.classList.add("SettingsButton"); @@ -328,6 +333,7 @@ class SelectInput implements OptionsElement{ options: string[]; index: number; select!: WeakRef; + radio:boolean; get value(){ return this.index; } @@ -336,15 +342,61 @@ class SelectInput implements OptionsElement{ onSubmit: (str: number) => void, options: string[], owner: Options, - { defaultIndex = 0 } = {} + { defaultIndex = 0,radio=false } = {} ){ this.label = label; this.index = defaultIndex; this.owner = owner; this.onSubmit = onSubmit; this.options = options; + this.radio=radio; } generateHTML(): HTMLDivElement{ + if(this.radio){ + const map=new WeakMap(); + const div = document.createElement("div"); + const fieldset = document.createElement("fieldset"); + fieldset.addEventListener("change", ()=>{ + let i = -1; + for(const thing of Array.from(fieldset.children)){ + i++; + if(i === 0){ + continue; + } + const checkbox = thing.children[0].children[0] as HTMLInputElement; + if(checkbox.checked){ + this.onChange(map.get(checkbox)); + } + } + }); + const legend = document.createElement("legend"); + legend.textContent = this.label; + fieldset.appendChild(legend); + let i = 0; + for(const thing of this.options){ + const div = document.createElement("div"); + const input = document.createElement("input"); + input.classList.add("radio"); + input.type = "radio"; + input.name = this.label; + input.value = thing; + map.set(input,i); + if(i === this.index){ + input.checked = true; + } + const label = document.createElement("label"); + + label.appendChild(input); + const span = document.createElement("span"); + span.textContent = thing; + label.appendChild(span); + div.appendChild(label); + fieldset.appendChild(div); + i++; + } + div.appendChild(fieldset); + return div; + } const div = document.createElement("div"); const span = document.createElement("span"); span.textContent = this.label; @@ -353,7 +405,7 @@ class SelectInput implements OptionsElement{ selectSpan.classList.add("selectspan"); const select = document.createElement("select"); - select.onchange = this.onChange.bind(this); + select.onchange = this.onChange.bind(this,-1); for(const thing of this.options){ const option = document.createElement("option"); option.textContent = thing; @@ -368,8 +420,13 @@ class SelectInput implements OptionsElement{ div.append(selectSpan); return div; } - private onChange(){ + private onChange(index=-1){ this.owner.changed(); + if(index!==-1){ + this.onchange(index); + this.index = index; + return; + } const select = this.select.deref(); if(select){ const value = select.selectedIndex; @@ -524,7 +581,7 @@ class Float{ /** * This is a simple wrapper class for Options to make it happy so it can be used outside of Settings. */ - constructor(name:string, options={ ltr:false, noSubmit:false}){ + constructor(name:string, options={ ltr:false, noSubmit:true}){ this.options=new Options(name,this,options) } changed=()=>{}; @@ -532,6 +589,38 @@ class Float{ return this.options.generateHTML(); } } +class BDialog{ + float:Float; + get options(){ + return this.float.options; + } + background=new WeakRef(document.createElement("div")); + constructor(name:string, { ltr=false, noSubmit=true}={}){ + this.float=new Float(name,{ltr,noSubmit}); + } + show(){ + const background = document.createElement("div"); + background.classList.add("background"); + const center=this.float.generateHTML(); + center.classList.add("centeritem","nonimagecenter"); + center.classList.remove("titlediv"); + background.append(center); + center.onclick=e=>{ + e.stopImmediatePropagation(); + } + document.body.append(background); + this.background=new WeakRef(background); + background.onclick = _=>{ + background.remove(); + }; + } + hide(){ + const background=this.background.deref(); + if(!background) return; + background.remove(); + } +} +export{BDialog}; class Options implements OptionsElement{ name: string; haschanged = false; @@ -571,6 +660,12 @@ class Options implements OptionsElement{ this.generate(options); return options; } + addButtons(name: string, { top = false } = {}){ + const buttons = new Buttons(name, { top }); + this.options.push(buttons); + this.generate(buttons); + return buttons; + } subOptions: Options | Form | undefined; genTop(){ const container = this.container.deref(); @@ -596,7 +691,7 @@ class Options implements OptionsElement{ } addSubForm( name: string, - onSubmit: (arg1: object) => void, + onSubmit: (arg1: object,sent:object) => void, { ltr = false, submitText = "Submit", @@ -626,10 +721,10 @@ class Options implements OptionsElement{ label: string, onSubmit: (str: number) => void, selections: string[], - { defaultIndex = 0 } = {} + { defaultIndex = 0,radio=false } = {} ){ const select = new SelectInput(label, onSubmit, selections, this, { - defaultIndex, + defaultIndex,radio }); this.options.push(select); this.generate(select); @@ -717,7 +812,7 @@ class Options implements OptionsElement{ } addForm( name: string, - onSubmit: (arg1: object) => void, + onSubmit: (arg1: object,sent:object) => void, { ltr = false, submitText = "Submit", @@ -901,7 +996,7 @@ class Form implements OptionsElement{ constructor( name: string, owner: Options, - onSubmit: (arg1: object) => void, + onSubmit: (arg1: object,sent:object) => void, { ltr = false, submitText = I18n.getTranslation("submit"), @@ -934,7 +1029,7 @@ class Form implements OptionsElement{ } addSubForm( name: string, - onSubmit: (arg1: object) => void, + onSubmit: (arg1: object,sent:object) => void, { ltr = false, submitText = I18n.getTranslation("submit"), @@ -956,16 +1051,16 @@ class Form implements OptionsElement{ (this.button.deref() as HTMLElement).hidden=false; } } - selectMap=new WeakMap(); + selectMap=new WeakMap(); addSelect( label: string, formName: string, selections: string[], - { defaultIndex = 0, required = false}={}, - correct:string[]=selections + { defaultIndex = 0, required = false,radio=false}={}, + correct:(string|number)[]=selections ){ const select = this.options.addSelect(label, _=>{}, selections, { - defaultIndex, + defaultIndex,radio }); this.selectMap.set(select,correct); this.names.set(formName, select); @@ -1084,7 +1179,7 @@ class Form implements OptionsElement{ } return div; } - onSubmit: (arg1: object) => void; + onSubmit: ((arg1: object,sent:object) => void )|((arg1: object,sent:object) => Promise ); watchForChange(func: (arg1: object) => void){ this.onSubmit = func; } @@ -1187,14 +1282,14 @@ class Form implements OptionsElement{ if(_==="") return {}; return JSON.parse(_) }) - .then(json=>{ + .then(async json=>{ if(json.errors){ if(this.errors(json)){ return; } } try{ - this.onSubmit(json); + await this.onSubmit(json,build); }catch(e){ console.error(e); if(e instanceof FormError){ @@ -1211,7 +1306,7 @@ class Form implements OptionsElement{ }); }else{ try{ - this.onSubmit(build); + await this.onSubmit(build,build); }catch(e){ if(e instanceof FormError){ const elm = this.options.html.get(e.elem); diff --git a/src/webpage/style.css b/src/webpage/style.css index 87cbc96..cc15662 100644 --- a/src/webpage/style.css +++ b/src/webpage/style.css @@ -1614,12 +1614,12 @@ img.bigembedimg { gap: 8px; overflow-y: auto; } -.nonimagecenter .flexttb, .nonimagecenter .flexltr { +.nonimagecenter & .flexttb, .nonimagecenter & .flexltr { flex: 1; gap: 8px; } .nonimagecenter > .flexttb, .nonimagecenter > .flexltr { - padding: 16px; + padding: 16px !important; background: var(--primary-bg); border-radius: 8px; } @@ -1758,6 +1758,12 @@ fieldset input[type="radio"] { .Buttons { flex: 1; } +.settingbuttons.flexltr{ + width: 100%; + .SettingsButton{ + width:auto; + } +} .settingbuttons { flex: none; width: 192px; @@ -1800,7 +1806,8 @@ fieldset input[type="radio"] { } .optionElement, .FormSettings > button { margin: 16px 16px 0 16px; - word-break: break-word; + /* word-break: break-word; */ + overflow: hidden; } .optionElement:has(.optionElement) { margin: 0; @@ -1915,7 +1922,7 @@ fieldset input[type="radio"] { height: calc(100svh - 50px); } .flexspace { - flex-direction: column; + /*flex-direction: column;*/ } .optionElement input[type="text"], .optionElement textarea, diff --git a/translations/en.json b/translations/en.json index e1629e4..22ce38d 100644 --- a/translations/en.json +++ b/translations/en.json @@ -152,7 +152,7 @@ "nsfw:":"NSFW:", "selectType":"Select channel type", "selectName":"Name of channel", - "selectCatName":"Name of channel", + "selectCatName":"Name of category", "createChannel":"Create channel", "createCatagory":"Create category" }, @@ -219,7 +219,7 @@ "selectnoti":"Select notifications type", "all":"all", "onlyMentions":"only mentions", - "none":"node", + "none":"none", "confirmLeave":"Are you sure you want to leave?", "yesLeave":"Yes, I'm sure", "noLeave":"Nevermind", @@ -231,7 +231,8 @@ "loadingDiscovery":"Loading...", "disoveryTitle":"Guild discovery ($1) {{PLURAL:$1|entry|entries}}", "emptytitle":"Weird spot", - "emptytext":"You're in a weird spot, this guild has no channels" + "emptytext":"You're in a weird spot, this guild has no channels", + "default":"Default ($1)" }, "role":{ "displaySettings":"Display settings", @@ -345,7 +346,9 @@ "longInvitedBy":"$1 invited you to join $2", "loginOrCreateAccount":"Login or create an account ⇌", "joinUsing":"Join using invite", - "inviteLinkCode":"Invite Link/Code" + "inviteLinkCode":"Invite Link/Code", + "subtext":"to $1 in $2", + "expireAfter":"Expire after:" }, "friends":{ "blocked":"Blocked",