diff --git a/src/webpage/file.ts b/src/webpage/file.ts
index 05d8706..6663eb6 100644
--- a/src/webpage/file.ts
+++ b/src/webpage/file.ts
@@ -2,6 +2,7 @@ import {Message} from "./message.js";
import {filejson} from "./jsontypes.js";
import {ImagesDisplay} from "./disimg.js";
import {makePlayBox, MediaPlayer} from "./media.js";
+import {I18n} from "./i18n.js";
class File {
owner: Message | null;
id: string;
@@ -24,7 +25,17 @@ class File {
this.content_type = fileJSON.content_type;
this.size = fileJSON.size;
}
- getHTML(temp: boolean = false, fullScreen = false): HTMLElement {
+ getHTML(temp: boolean = false, fullScreen = false, OSpoiler = false): HTMLElement {
+ function makeSpoilerHTML(): HTMLElement {
+ const spoil = document.createElement("div");
+ spoil.classList.add("fSpoil");
+ const stext = document.createElement("span");
+ stext.textContent = I18n.spoiler();
+ spoil.append(stext);
+ spoil.onclick = () => spoil.remove();
+ return spoil;
+ }
+ OSpoiler ||= this.filename.startsWith("SPOILER_");
const src = this.proxy_url || this.url;
if (this.width && this.height) {
let scale = 1;
@@ -60,6 +71,9 @@ class File {
div.style.height = this.height + "px";
}
if (!fullScreen) {
+ if (OSpoiler) {
+ div.append(makeSpoilerHTML());
+ }
return div;
} else {
return img;
@@ -75,11 +89,25 @@ class File {
video.width = this.width;
video.height = this.height;
}
+ if (OSpoiler) {
+ const div = document.createElement("div");
+ div.style.setProperty("position", "relative");
+ div.append(video, makeSpoilerHTML());
+ return div;
+ }
return video;
} else if (this.content_type.startsWith("audio/")) {
- return this.getAudioHTML();
+ const a = this.getAudioHTML();
+ if (OSpoiler) {
+ a.append(makeSpoilerHTML());
+ }
+ return a;
} else {
- return this.createunknown();
+ const uk = this.createunknown();
+ if (OSpoiler) {
+ uk.append(makeSpoilerHTML());
+ }
+ return uk;
}
}
private getAudioHTML() {
@@ -88,10 +116,12 @@ class File {
}
upHTML(files: Blob[], file: globalThis.File): HTMLElement {
const div = document.createElement("div");
- const contained = this.getHTML(true);
+ let contained = this.getHTML(true, false, file.name.startsWith("SPOILER_"));
div.classList.add("containedFile");
div.append(contained);
const controls = document.createElement("div");
+ controls.classList.add("controls");
+
const garbage = document.createElement("button");
const icon = document.createElement("span");
icon.classList.add("svgicon", "svg-delete");
@@ -100,9 +130,37 @@ class File {
div.remove();
files.splice(files.indexOf(file), 1);
};
- controls.classList.add("controls");
+
+ const spoiler = document.createElement("button");
+ const sicon = document.createElement("span");
+ sicon.classList.add(
+ "svgicon",
+ file.name.startsWith("SPOILER_") ? "svg-unspoiler" : "svg-spoiler",
+ );
+ spoiler.append(sicon);
+ spoiler.onclick = (_) => {
+ if (file.name.startsWith("SPOILER_")) {
+ const name = file.name.split("SPOILER_");
+ name.shift();
+ file = files[files.indexOf(file)] = new globalThis.File([file], name.join("SPOILER_"), {
+ type: file.type,
+ });
+ sicon.classList.add("svg-spoiler");
+ sicon.classList.remove("svg-unspoiler");
+ } else {
+ file = files[files.indexOf(file)] = new globalThis.File([file], "SPOILER_" + file.name, {
+ type: file.type,
+ });
+ sicon.classList.add("svg-unspoiler");
+ sicon.classList.remove("svg-spoiler");
+ }
+ contained.remove();
+ contained = this.getHTML(true, false, file.name.startsWith("SPOILER_"));
+ div.append(contained);
+ };
+
div.append(controls);
- controls.append(garbage);
+ controls.append(spoiler, garbage);
return div;
}
static initFromBlob(file: globalThis.File) {
diff --git a/src/webpage/guild.ts b/src/webpage/guild.ts
index 67eb539..551713c 100644
--- a/src/webpage/guild.ts
+++ b/src/webpage/guild.ts
@@ -317,6 +317,34 @@ class Guild extends SnowFlake {
genDiv();
emoji.addHTMLArea(containdiv);
}
+ (async () => {
+ const widgetMenu = settings.addButton(I18n.widget());
+ const cur = (await (
+ await fetch(this.info.api + "/guilds/" + this.id + "/widget", {
+ headers: this.headers,
+ })
+ ).json()) as {
+ enabled: boolean;
+ channel_id?: null | string;
+ };
+ const form = widgetMenu.addForm("", () => {}, {
+ traditionalSubmit: true,
+ fetchURL: this.info.api + "/guilds/" + this.id + "/widget",
+ headers: this.headers,
+ method: "PATCH",
+ });
+ form.addCheckboxInput(I18n.widgetEnabled(), "enabled", {initState: cur.enabled});
+ const channels = this.channels.filter((_) => _.type !== 4);
+ form.addSelect(
+ I18n.channel.name(),
+ "channel_id",
+ channels.map((_) => _.name),
+ {
+ defaultIndex: channels.findIndex((_) => _.id == cur.channel_id),
+ },
+ channels.map((_) => _.id),
+ );
+ })();
const webhooks = settings.addButton(I18n.webhooks.base());
webhookMenu(this, this.info.api + `/guilds/${this.id}/webhooks`, webhooks);
settings.show();
diff --git a/src/webpage/icons/spoiler.svg b/src/webpage/icons/spoiler.svg
new file mode 100644
index 0000000..f45543f
--- /dev/null
+++ b/src/webpage/icons/spoiler.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/webpage/icons/unspoiler.svg b/src/webpage/icons/unspoiler.svg
new file mode 100644
index 0000000..032375f
--- /dev/null
+++ b/src/webpage/icons/unspoiler.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/webpage/style.css b/src/webpage/style.css
index 56a114a..aa5053d 100644
--- a/src/webpage/style.css
+++ b/src/webpage/style.css
@@ -36,6 +36,7 @@ body {
flex-grow: 0;
flex-shrink: 0;
height: 52px;
+ position: relative;
* {
margin: 2px;
@@ -333,6 +334,12 @@ textarea {
display: block;
mask-size: cover !important;
}
+.svg-spoiler {
+ mask: url(/icons/spoiler.svg);
+}
+.svg-unspoiler {
+ mask: url(/icons/unspoiler.svg);
+}
.svg-soundMore {
mask: url(/icons/soundMore.svg);
}
@@ -1094,6 +1101,7 @@ span.instanceStatus {
}
.messageimgdiv {
height: 100%;
+ position: relative;
}
.messageimg {
height: 100%;
@@ -1223,6 +1231,29 @@ span.instanceStatus {
.messagediv:hover {
background: var(--primary-hover);
}
+.fSpoil {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ backdrop-filter: blur(20px);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ transition: backdrop-filter 0.4s;
+ span {
+ background: var(--spoiler-bg);
+ padding: 3px 6px;
+ border-radius: 6px;
+ }
+}
+.fSpoil:hover {
+ backdrop-filter: blur(15px);
+ span {
+ background: var(--spoiler-hover);
+ }
+}
.messageButtons,
.controls {
position: absolute;
@@ -1262,6 +1293,7 @@ span.instanceStatus {
top: 6px;
right: 6px;
box-shadow: 0 0 1.5px var(--primary-text-soft);
+ z-index: 1;
}
.message {
padding-right: 28px;
@@ -1603,6 +1635,7 @@ img.bigembedimg {
padding: 4px;
background: var(--secondary-bg);
border-radius: 4px;
+ position: relative;
}
.acceptinvbutton {
width: calc(100% - 24px);
diff --git a/translations/en.json b/translations/en.json
index 0efe2e6..67f8265 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -144,7 +144,9 @@
"typing": "$2 {{PLURAL:$1|is|are}} typing",
"noMessages": "No messages appear to be here, be the first to say something!",
"blankMessage": "Blank Message",
+ "spoiler": "Spoiler",
"channel": {
+ "name": "Channel",
"copyId": "Copy channel id",
"markRead": "Mark as read",
"settings": "Settings",
@@ -509,6 +511,8 @@
"name:": "Name:",
"confirmDel": "Are you sure you want to delete this emoji?"
},
+ "widget": "Guild Widget",
+ "widgetEnabled": "Widget enabled",
"incorrectURLS": "## This instance has likely sent the incorrect URLs.\n### If you're the instance owner please see [here](https://docs.spacebar.chat/setup/server/) under *Connecting from remote machines* to correct the issue.\n Would you like Jank Client to automatically try to fix this error to let you connect to the instance?",
"jankInfo": "Client Information",
"clientDesc": "Client version: $1\n\n[Join the official Jank Client guild]($2/invite/USgYJo?instance=https%3A%2F%2Fspacebar.chat)\n\n[Help translate Jank Client](https://translatewiki.net/wiki/Translating:JankClient#sortable:3=desc) \n\n[Help create Jank client](https://github.com/MathMan05/JankClient)\n\n[Help maintain the server jank client relies on](https://github.com/spacebarchat/server)\n\nCalculated rights: $3",