add image spoilers
This commit is contained in:
parent
54416197de
commit
ea7769ce85
6 changed files with 131 additions and 6 deletions
|
@ -2,6 +2,7 @@ import {Message} from "./message.js";
|
||||||
import {filejson} from "./jsontypes.js";
|
import {filejson} from "./jsontypes.js";
|
||||||
import {ImagesDisplay} from "./disimg.js";
|
import {ImagesDisplay} from "./disimg.js";
|
||||||
import {makePlayBox, MediaPlayer} from "./media.js";
|
import {makePlayBox, MediaPlayer} from "./media.js";
|
||||||
|
import {I18n} from "./i18n.js";
|
||||||
class File {
|
class File {
|
||||||
owner: Message | null;
|
owner: Message | null;
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -24,7 +25,17 @@ class File {
|
||||||
this.content_type = fileJSON.content_type;
|
this.content_type = fileJSON.content_type;
|
||||||
this.size = fileJSON.size;
|
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;
|
const src = this.proxy_url || this.url;
|
||||||
if (this.width && this.height) {
|
if (this.width && this.height) {
|
||||||
let scale = 1;
|
let scale = 1;
|
||||||
|
@ -60,6 +71,9 @@ class File {
|
||||||
div.style.height = this.height + "px";
|
div.style.height = this.height + "px";
|
||||||
}
|
}
|
||||||
if (!fullScreen) {
|
if (!fullScreen) {
|
||||||
|
if (OSpoiler) {
|
||||||
|
div.append(makeSpoilerHTML());
|
||||||
|
}
|
||||||
return div;
|
return div;
|
||||||
} else {
|
} else {
|
||||||
return img;
|
return img;
|
||||||
|
@ -75,11 +89,25 @@ class File {
|
||||||
video.width = this.width;
|
video.width = this.width;
|
||||||
video.height = this.height;
|
video.height = this.height;
|
||||||
}
|
}
|
||||||
|
if (OSpoiler) {
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.style.setProperty("position", "relative");
|
||||||
|
div.append(video, makeSpoilerHTML());
|
||||||
|
return div;
|
||||||
|
}
|
||||||
return video;
|
return video;
|
||||||
} else if (this.content_type.startsWith("audio/")) {
|
} else if (this.content_type.startsWith("audio/")) {
|
||||||
return this.getAudioHTML();
|
const a = this.getAudioHTML();
|
||||||
|
if (OSpoiler) {
|
||||||
|
a.append(makeSpoilerHTML());
|
||||||
|
}
|
||||||
|
return a;
|
||||||
} else {
|
} else {
|
||||||
return this.createunknown();
|
const uk = this.createunknown();
|
||||||
|
if (OSpoiler) {
|
||||||
|
uk.append(makeSpoilerHTML());
|
||||||
|
}
|
||||||
|
return uk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private getAudioHTML() {
|
private getAudioHTML() {
|
||||||
|
@ -88,10 +116,12 @@ class File {
|
||||||
}
|
}
|
||||||
upHTML(files: Blob[], file: globalThis.File): HTMLElement {
|
upHTML(files: Blob[], file: globalThis.File): HTMLElement {
|
||||||
const div = document.createElement("div");
|
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.classList.add("containedFile");
|
||||||
div.append(contained);
|
div.append(contained);
|
||||||
const controls = document.createElement("div");
|
const controls = document.createElement("div");
|
||||||
|
controls.classList.add("controls");
|
||||||
|
|
||||||
const garbage = document.createElement("button");
|
const garbage = document.createElement("button");
|
||||||
const icon = document.createElement("span");
|
const icon = document.createElement("span");
|
||||||
icon.classList.add("svgicon", "svg-delete");
|
icon.classList.add("svgicon", "svg-delete");
|
||||||
|
@ -100,9 +130,37 @@ class File {
|
||||||
div.remove();
|
div.remove();
|
||||||
files.splice(files.indexOf(file), 1);
|
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);
|
div.append(controls);
|
||||||
controls.append(garbage);
|
controls.append(spoiler, garbage);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
static initFromBlob(file: globalThis.File) {
|
static initFromBlob(file: globalThis.File) {
|
||||||
|
|
|
@ -317,6 +317,34 @@ class Guild extends SnowFlake {
|
||||||
genDiv();
|
genDiv();
|
||||||
emoji.addHTMLArea(containdiv);
|
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());
|
const webhooks = settings.addButton(I18n.webhooks.base());
|
||||||
webhookMenu(this, this.info.api + `/guilds/${this.id}/webhooks`, webhooks);
|
webhookMenu(this, this.info.api + `/guilds/${this.id}/webhooks`, webhooks);
|
||||||
settings.show();
|
settings.show();
|
||||||
|
|
1
src/webpage/icons/spoiler.svg
Normal file
1
src/webpage/icons/spoiler.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g stroke="red" stroke-linecap="round" stroke-linejoin="round"><path fill="none" stroke-width="72.7" d="M45 247c71-72 143-145 213-145 71 0 140 73 209 145m1 9c-72 73-144 144-214 144-71 0-140-71-208-144"/><circle cx="256.5" cy="251" r="33" fill="red" stroke-width="80"/></g></svg>
|
After Width: | Height: | Size: 340 B |
1
src/webpage/icons/unspoiler.svg
Normal file
1
src/webpage/icons/unspoiler.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g fill="red" stroke="red" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="m94 356 52-51c-18-16-36-34-54-54 28-28 56-54 82-74 33-25 62-38 84-38 13 0 29 4 45 13l54-53c-30-19-63-33-99-33-48 0-89 23-128 53-39 29-75 66-111 102a36 36 0 0 0-10 32 36 36 0 0 0 10 28c24 26 49 52 75 75zm327-207-53 51 53 52c-29 28-57 55-83 74-32 25-61 38-84 38-12 0-27-4-42-11l-54 53c29 18 61 31 96 31 47 0 89-23 128-53 39-29 76-66 112-103a36 36 0 0 0 9-32 36 36 0 0 0-10-27l-72-73z" overflow="visible"/><path stroke="none" d="m329 239-86 84 14 1a74 74 0 0 0 72-85zm-144 28 89-87-17-2a74 74 0 0 0-72 89z" overflow="visible"/><path stroke-width="34.9" d="M450 64 63 442v0"/></g></svg>
|
After Width: | Height: | Size: 741 B |
|
@ -36,6 +36,7 @@ body {
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
height: 52px;
|
height: 52px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
* {
|
* {
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
|
@ -333,6 +334,12 @@ textarea {
|
||||||
display: block;
|
display: block;
|
||||||
mask-size: cover !important;
|
mask-size: cover !important;
|
||||||
}
|
}
|
||||||
|
.svg-spoiler {
|
||||||
|
mask: url(/icons/spoiler.svg);
|
||||||
|
}
|
||||||
|
.svg-unspoiler {
|
||||||
|
mask: url(/icons/unspoiler.svg);
|
||||||
|
}
|
||||||
.svg-soundMore {
|
.svg-soundMore {
|
||||||
mask: url(/icons/soundMore.svg);
|
mask: url(/icons/soundMore.svg);
|
||||||
}
|
}
|
||||||
|
@ -1094,6 +1101,7 @@ span.instanceStatus {
|
||||||
}
|
}
|
||||||
.messageimgdiv {
|
.messageimgdiv {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.messageimg {
|
.messageimg {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1223,6 +1231,29 @@ span.instanceStatus {
|
||||||
.messagediv:hover {
|
.messagediv:hover {
|
||||||
background: var(--primary-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,
|
.messageButtons,
|
||||||
.controls {
|
.controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -1262,6 +1293,7 @@ span.instanceStatus {
|
||||||
top: 6px;
|
top: 6px;
|
||||||
right: 6px;
|
right: 6px;
|
||||||
box-shadow: 0 0 1.5px var(--primary-text-soft);
|
box-shadow: 0 0 1.5px var(--primary-text-soft);
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.message {
|
.message {
|
||||||
padding-right: 28px;
|
padding-right: 28px;
|
||||||
|
@ -1603,6 +1635,7 @@ img.bigembedimg {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
background: var(--secondary-bg);
|
background: var(--secondary-bg);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.acceptinvbutton {
|
.acceptinvbutton {
|
||||||
width: calc(100% - 24px);
|
width: calc(100% - 24px);
|
||||||
|
|
|
@ -144,7 +144,9 @@
|
||||||
"typing": "$2 {{PLURAL:$1|is|are}} typing",
|
"typing": "$2 {{PLURAL:$1|is|are}} typing",
|
||||||
"noMessages": "No messages appear to be here, be the first to say something!",
|
"noMessages": "No messages appear to be here, be the first to say something!",
|
||||||
"blankMessage": "Blank Message",
|
"blankMessage": "Blank Message",
|
||||||
|
"spoiler": "Spoiler",
|
||||||
"channel": {
|
"channel": {
|
||||||
|
"name": "Channel",
|
||||||
"copyId": "Copy channel id",
|
"copyId": "Copy channel id",
|
||||||
"markRead": "Mark as read",
|
"markRead": "Mark as read",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
|
@ -509,6 +511,8 @@
|
||||||
"name:": "Name:",
|
"name:": "Name:",
|
||||||
"confirmDel": "Are you sure you want to delete this emoji?"
|
"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?",
|
"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",
|
"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",
|
"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",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue