diff --git a/src/webpage/channel.ts b/src/webpage/channel.ts index c18046d..e896e3e 100644 --- a/src/webpage/channel.ts +++ b/src/webpage/channel.ts @@ -1587,6 +1587,7 @@ class Channel extends SnowFlake { this.localuser.channelfocus.collectBox(); } const typebox = document.getElementById("typebox") as CustomHTMLDivElement; + typebox.style.setProperty("--channel-text", JSON.stringify(I18n.channel.typebox(this.name))); const md = typebox.markdown; md.owner = this; typebox.textContent = this.textSave; diff --git a/src/webpage/direct.ts b/src/webpage/direct.ts index e2a4f96..9e97706 100644 --- a/src/webpage/direct.ts +++ b/src/webpage/direct.ts @@ -9,12 +9,14 @@ import {SnowFlake} from "./snowflake.js"; import {Contextmenu} from "./contextmenu.js"; import {I18n} from "./i18n.js"; import {Dialog, Float, FormError} from "./settings.js"; +import {Discovery} from "./discovery.js"; class Direct extends Guild { channels: Group[]; getUnixTime(): number { throw new Error("Do not call this for Direct, it does not make sense"); } + discovery: Discovery; constructor(json: dirrectjson[], owner: Localuser) { super(-1, owner, null); this.message_notifications = 0; @@ -31,6 +33,7 @@ class Direct extends Guild { this.localuser.channelids.set(temp.id, temp); } this.headchannels = this.channels; + this.discovery = new Discovery(this); } createChannelpac(json: any) { const thischannel = new Group(json, this); @@ -86,6 +89,14 @@ class Direct extends Guild { ddiv.append(freindDiv, newDm, build); return ddiv; } + loadChannel(id?: string | null | undefined, addstate = true, message?: string) { + if (id === "discover") { + this.removePrevChannel(); + this.discovery.makeMenu(); + return; + } + super.loadChannel(id, addstate, message); + } makeGroup() { const dio = new Dialog(I18n.group.select()); const opt = dio.options; @@ -501,7 +512,11 @@ class Group extends Channel { this.icon = json.icon; + json.recipients = json.recipients.filter((_) => _.id !== this.localuser.user.id); const userSet = new Set(json.recipients.map((user) => new User(user, this.localuser))); + if (userSet.size === 0) { + userSet.add(this.localuser.user); + } this.users = [...userSet]; this.name = json.name || this.defaultName(); diff --git a/src/webpage/discovery.ts b/src/webpage/discovery.ts new file mode 100644 index 0000000..646c4c6 --- /dev/null +++ b/src/webpage/discovery.ts @@ -0,0 +1,200 @@ +import {Direct} from "./direct.js"; +import {I18n} from "./i18n.js"; +import {guildjson} from "./jsontypes.js"; +import {Dialog} from "./settings.js"; +import {createImg} from "./utils/utils.js"; + +export class Discovery { + owner: Direct; + get info() { + return this.owner.info; + } + get headers() { + return this.owner.headers; + } + get localuser() { + return this.owner.localuser; + } + constructor(owner: Direct) { + this.owner = owner; + } + async makeMenu() { + if (this.owner instanceof Direct) { + this.owner.freindDiv?.classList.remove("viewChannel"); + } + if (this.localuser.channelfocus) { + this.localuser.channelfocus.collectBox(); + } + history.pushState(["@me", "discover"], "", "/channels/@me/discover"); + this.localuser.pageTitle(I18n.discovery()); + + const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement; + channelTopic.removeAttribute("hidden"); + channelTopic.textContent = ""; + channelTopic.onclick = () => {}; + if (this.localuser.lookingguild) { + this.localuser.lookingguild.html.classList.remove("serveropen"); + } + + this.localuser.lookingguild = undefined; + this.localuser.channelfocus = undefined; + + const loading = document.getElementById("loadingdiv") as HTMLDivElement; + loading.classList.remove("loading"); + this.localuser.getSidePannel(); + + const messages = document.getElementById("scrollWrap") as HTMLDivElement; + for (const thing of Array.from(messages.getElementsByClassName("messagecontainer"))) { + thing.remove(); + } + + const channels = document.getElementById("channels") as HTMLDivElement; + channels.innerHTML = ""; + + const banner = document.getElementById("servertd") as HTMLDivElement; + banner.style.removeProperty("background-image"); + banner.classList.remove("Banner"); + banner.style.removeProperty("cursor"); + banner.onclick = () => {}; + + (document.getElementById("serverName") as HTMLElement).textContent = I18n.discovery(); + + const scrollWrap = document.getElementById("scrollWrap") as HTMLDivElement; + scrollWrap.innerHTML = ""; + + const content = document.createElement("div"); + content.classList.add("flexttb", "guildy", "messagecontainer"); + content.textContent = I18n.guild.loadingDiscovery(); + + scrollWrap.append(content); + + const guildsButton = document.createElement("button"); + guildsButton.textContent = I18n.guild.guilds(); + guildsButton.classList.add("discoverButton", "selected"); + channels.append(guildsButton); + + const res = await fetch(this.info.api + "/discoverable-guilds?limit=50", { + headers: this.headers, + }); + const json = await res.json(); + console.log([...json.guilds], json.guilds); + //@ts-ignore + json.guilds = json.guilds.sort((a, b) => { + return b.member_count - a.member_count; + }); + content.innerHTML = ""; + const title = document.createElement("h2"); + title.textContent = I18n.guild.disoveryTitle(json.guilds.length + ""); + content.appendChild(title); + + const guilds = document.createElement("div"); + guilds.id = "discovery-guild-content"; + + json.guilds.forEach((guild: guildjson["properties"]) => { + const content = document.createElement("div"); + content.classList.add("discovery-guild"); + const banner = this.getBannerURL(guild); + if (banner) { + banner.classList.add("banner"); + banner.crossOrigin = "anonymous"; + banner.alt = ""; + content.appendChild(banner); + } + + const nameContainer = document.createElement("div"); + nameContainer.classList.add("flex"); + const img = this.getIconURL(guild); + img.classList.add("icon"); + img.crossOrigin = "anonymous"; + + img.alt = ""; + nameContainer.appendChild(img); + + const name = document.createElement("h3"); + name.textContent = guild.name; + nameContainer.appendChild(name); + content.appendChild(nameContainer); + const desc = document.createElement("p"); + desc.textContent = guild.description; + content.appendChild(desc); + + content.addEventListener("click", async () => { + let guildObj = this.localuser.guildids.get(guild.id); + if (guildObj) { + guildObj.loadGuild(); + guildObj.loadChannel(); + return; + } + if (await this.confirmJoin(guild)) { + await this.join(guild); + } + }); + guilds.appendChild(content); + }); + content.appendChild(guilds); + } + getIconURL(guild: guildjson["properties"]) { + return createImg( + this.info.cdn + + (guild.icon + ? "/icons/" + guild.id + "/" + guild.icon + ".png?size=48" + : "/embed/avatars/3.png"), + ); + } + getBannerURL(guild: guildjson["properties"]) { + return ( + guild.banner && + createImg(this.info.cdn + "/icons/" + guild.id + "/" + guild.banner + ".png?size=256") + ); + } + async confirmJoin(guild: guildjson["properties"]) { + return new Promise((res) => { + const dio = new Dialog(I18n.guild.joinConfirm(guild.name)); + const opt = dio.options; + + const div = document.createElement("div"); + div.classList.add("flexltr", "guildPreview"); + const img = this.getIconURL(guild); + img.classList.add("icon"); + img.crossOrigin = "anonymous"; + img.alt = ""; + div.append(img); + const banner = this.getBannerURL(guild); + if (banner) { + banner.classList.add("banner"); + banner.crossOrigin = "anonymous"; + banner.alt = ""; + div.append(banner); + } + + opt.addHTMLArea(div); + opt.addText(I18n.guild.memberCount(guild.member_count + "")); + + if (guild.description) opt.addText(I18n.guild["description:"]() + "\n" + guild.description); + + const buttons = opt.addOptions("", {ltr: true}); + buttons.addButtonInput("", I18n.yes(), () => { + dio.hide(); + res(true); + }); + buttons.addButtonInput("", I18n.no(), () => { + dio.hide(); + res(false); + }); + dio.show(); + }); + } + async join(guild: guildjson["properties"]) { + await fetch(this.info.api + "/guilds/" + guild.id + "/members/@me", { + method: "PUT", + headers: this.headers, + }); + let guildObj = this.localuser.guildids.get(guild.id); + while (!guildObj) { + guildObj = this.localuser.guildids.get(guild.id); + await new Promise((res) => setTimeout(res, 100)); + } + guildObj.loadGuild(); + guildObj.loadChannel(); + } +} diff --git a/src/webpage/guild.ts b/src/webpage/guild.ts index 9d935f5..c9027ac 100644 --- a/src/webpage/guild.ts +++ b/src/webpage/guild.ts @@ -1473,7 +1473,6 @@ class Guild extends SnowFlake { divy.appendChild(img); if (guild instanceof Guild && autoLink) { img.onclick = () => { - console.log(guild.loadGuild); guild.loadGuild(); guild.loadChannel(); }; diff --git a/src/webpage/localuser.ts b/src/webpage/localuser.ts index a361529..6757413 100644 --- a/src/webpage/localuser.ts +++ b/src/webpage/localuser.ts @@ -698,6 +698,10 @@ class Localuser { this.guildids.delete(temp.d.id); this.guilds.splice(this.guilds.indexOf(guildy), 1); guildy.html.remove(); + if (guildy === this.lookingguild) { + this.guildids.get("@me")?.loadGuild(); + this.guildids.get("@me")?.loadChannel(); + } } break; } @@ -1229,6 +1233,7 @@ class Localuser { } this.goToChannel(channelid, false, messageid); } + gotoid: string | undefined; async goToChannel(channelid: string, addstate = true, messageid: undefined | string = undefined) { const channel = this.channelids.get(channelid); @@ -1864,76 +1869,7 @@ class Localuser { ).json(); } async guildDiscovery() { - const content = document.createElement("div"); - content.classList.add("flexttb", "guildy"); - content.textContent = I18n.guild.loadingDiscovery(); - const full = new Dialog(""); - full.options.addHTMLArea(content); - full.show(); - - const res = await fetch(this.info.api + "/discoverable-guilds?limit=50", { - headers: this.headers, - }); - const json = await res.json(); - console.log([...json.guilds], json.guilds); - //@ts-ignore - json.guilds = json.guilds.sort((a, b) => { - return b.member_count - a.member_count; - }); - content.innerHTML = ""; - const title = document.createElement("h2"); - title.textContent = I18n.guild.disoveryTitle(json.guilds.length + ""); - content.appendChild(title); - - const guilds = document.createElement("div"); - guilds.id = "discovery-guild-content"; - - json.guilds.forEach((guild: guildjson["properties"]) => { - const content = document.createElement("div"); - content.classList.add("discovery-guild"); - - if (guild.banner) { - const banner = createImg( - this.info.cdn + "/icons/" + guild.id + "/" + guild.banner + ".png?size=256", - ); - banner.classList.add("banner"); - banner.crossOrigin = "anonymous"; - banner.alt = ""; - content.appendChild(banner); - } - - const nameContainer = document.createElement("div"); - nameContainer.classList.add("flex"); - const img = createImg( - this.info.cdn + - (guild.icon - ? "/icons/" + guild.id + "/" + guild.icon + ".png?size=48" - : "/embed/avatars/3.png"), - ); - img.classList.add("icon"); - img.crossOrigin = "anonymous"; - - img.alt = ""; - nameContainer.appendChild(img); - - const name = document.createElement("h3"); - name.textContent = guild.name; - nameContainer.appendChild(name); - content.appendChild(nameContainer); - const desc = document.createElement("p"); - desc.textContent = guild.description; - content.appendChild(desc); - - content.addEventListener("click", async () => { - const joinRes = await fetch(this.info.api + "/guilds/" + guild.id + "/members/@me", { - method: "PUT", - headers: this.headers, - }); - if (joinRes.ok) full.hide(); - }); - guilds.appendChild(content); - }); - content.appendChild(guilds); + this.guildids.get("@me")?.loadChannel("discover"); } messageCreate(messagep: messageCreateJson): void { messagep.d.guild_id ??= "@me"; diff --git a/src/webpage/style.css b/src/webpage/style.css index 311b4a4..9da75a3 100644 --- a/src/webpage/style.css +++ b/src/webpage/style.css @@ -477,6 +477,17 @@ audio::-webkit-media-controls-panel { .joinb:hover { background: color-mix(in srgb, var(--green) 80%, transparent); } +.discoverButton { + width: calc(100% - 10px); + text-align: center; + margin: 5px; + box-sizing: border-box; + background: #00000029; + padding: 10px; + &.selected { + background: #00000050; + } +} button, input::file-selector-button, select { @@ -1820,6 +1831,12 @@ span.instanceStatus { margin-right: 0.03in; padding: 10px 0; } +#typebox:empty:before, +#typebox:has(span:empty):before { + content: var(--channel-text); + opacity: 0.5; + position: absolute; +} .outerTypeBox { max-height: 50svh; padding: 10px 10px; @@ -3067,10 +3084,14 @@ fieldset input[type="radio"] { max-height: unset; width: auto; } +#typediv[style*="hidden"] { + height: 0px; +} .guildy { - height: 80svh; - width: 80svw; gap: 6px; + height: 100%; + padding: 10px; + box-sizing: border-box; } #discovery-guild-content { flex: 1; @@ -3189,6 +3210,11 @@ fieldset input[type="radio"] { align-self: center; cursor: pointer; } +.centeritem { + .fadeHTMLArea { + animation-duration: 0s; + } +} .fadeHTMLArea { position: absolute; width: 100%; @@ -3196,12 +3222,12 @@ fieldset input[type="radio"] { background: var(--settings-bg); animation-duration: 0.2s; animation-name: fadeOldSettings; + @media screen and (max-width: 600px) { animation-duration: 0s; } animation-timing-function: ease-in; z-index: 900; - height: 100%; &:empty { display: none; } @@ -3246,7 +3272,6 @@ fieldset input[type="radio"] { animation-timing-function: ease-in; } .titlediv { - height: 100%; } .flexspace { padding-bottom: 32px; @@ -3378,7 +3403,7 @@ fieldset input[type="radio"] { .optionElement input[type="text"], .optionElement textarea, .optionElement .fileinputdiv { - width: 500px; + max-width: 500px; } #app-list-container div, #connection-container div { @@ -4133,3 +4158,13 @@ img.error::after { margin-bottom: 0px; } } +.guildPreview { + .banner { + position: relative !important; + margin-left: 10px; + border-radius: 10px; + } + .icon { + flex-shrink: 0; + } +} diff --git a/translations/en.json b/translations/en.json index af663f1..e3eff44 100644 --- a/translations/en.json +++ b/translations/en.json @@ -191,6 +191,7 @@ "searchGifs": "Search Tenor", "muteDuration":"Unmute in:", "channel": { + "typebox":"Message in $1", "creating": "Creating channel", "name": "Channel", "copyId": "Copy channel id", @@ -314,7 +315,11 @@ "nevermind": "Nevermind", "submit": "submit", "edit": "Edit", + "discovery":"Discovery", "guild": { + "memberCount":"$1 {{PLURAL:$1|member|members}}", + "joinConfirm":"Join $1?", + "guilds":"Guilds", "template": "Template:", "admins":"Find Admins", "adminMenu":{