Restore emoji textures in nicknames, mentions and roles

This commit is contained in:
ohmwraith
2026-04-26 02:05:57 +03:00
parent 43dd6f4615
commit 044cb495ce
6 changed files with 50 additions and 4 deletions
+10
View File
@@ -5,6 +5,7 @@ import {Guild} from "./guild.js";
import {I18n} from "./i18n.js";
import {Dialog} from "./settings.js";
import {Contextmenu} from "./contextmenu.js";
import {setTextWithWrappedEmoji} from "./utils/utils.js";
const linkMenu = new Contextmenu<string, void>("copyLink", true);
linkMenu.addButton(
() => I18n.copyRegLink(),
@@ -629,6 +630,7 @@ class MarkDown {
mention.classList.add("mentionMD");
mention.contentEditable = "false";
mention.textContent = everyone ? "@everyone" : "@here";
setTextWithWrappedEmoji(mention, mention.textContent || "");
appendcurrent();
span.appendChild(mention);
mention.setAttribute("real", everyone ? `@everyone` : "@here");
@@ -670,17 +672,21 @@ class MarkDown {
const role = this.channel.guild.roleids.get(id);
if (role) {
mention.textContent = `@${role.name}`;
setTextWithWrappedEmoji(mention, mention.textContent || "");
mention.style.color = `var(--role-${role.id})`;
} else {
mention.textContent = I18n.guild.unknownRole();
setTextWithWrappedEmoji(mention, mention.textContent || "");
}
}
} else {
(async () => {
mention.textContent = I18n.userping.resolving();
setTextWithWrappedEmoji(mention, mention.textContent || "");
const user = await this.localuser?.getUser(id);
if (user) {
mention.textContent = `@${user.name}`;
setTextWithWrappedEmoji(mention, mention.textContent || "");
let guild: null | Guild = null;
if (this.channel) {
guild = this.channel.guild;
@@ -692,11 +698,13 @@ class MarkDown {
guild.resolveMember(user).then((member) => {
if (member) {
mention.textContent = `@${member.name}`;
setTextWithWrappedEmoji(mention, mention.textContent || "");
}
});
}
} else {
mention.textContent = I18n.userping.unknown();
setTextWithWrappedEmoji(mention, mention.textContent || "");
}
})();
}
@@ -705,6 +713,7 @@ class MarkDown {
const channel = this.localuser.channelids.get(id);
if (channel) {
mention.textContent = `#${channel.name}`;
setTextWithWrappedEmoji(mention, mention.textContent || "");
if (!keep && !stdsize) {
mention.onclick = (_) => {
if (!this.localuser) return;
@@ -713,6 +722,7 @@ class MarkDown {
}
} else {
mention.textContent = "#unknown";
setTextWithWrappedEmoji(mention, mention.textContent || "");
}
break;
}
+3 -1
View File
@@ -6,6 +6,7 @@ import {highMemberJSON, memberjson, presencejson} from "./jsontypes.js";
import {I18n} from "./i18n.js";
import {Dialog, Options, Settings} from "./settings.js";
import {CDNParams} from "./utils/cdnParams.js";
import {setTextWithWrappedEmoji} from "./utils/utils.js";
class Member extends SnowFlake {
static already = {};
@@ -34,6 +35,7 @@ class Member extends SnowFlake {
elms = new Set<WeakRef<HTMLElement>>();
subName(elm: HTMLElement) {
this.elms.add(new WeakRef(elm));
setTextWithWrappedEmoji(elm, this.name);
}
nameChange() {
for (const ref of this.elms) {
@@ -42,7 +44,7 @@ class Member extends SnowFlake {
this.elms.delete(ref);
continue;
}
elm.textContent = this.name;
setTextWithWrappedEmoji(elm, this.name);
}
}
commuicationDisabledLeft() {
+2 -1
View File
@@ -8,6 +8,7 @@ import {OptionsElement, Buttons, Dialog, ColorInput} from "./settings.js";
import {Contextmenu} from "./contextmenu.js";
import {Channel} from "./channel.js";
import {I18n} from "./i18n.js";
import {setTextWithWrappedEmoji} from "./utils/utils.js";
class Role extends SnowFlake {
permissions: Permissions;
@@ -647,7 +648,7 @@ class RoleList extends Buttons {
this.buttonMap.set(thing[0], button);
button.classList.add("SettingsButton");
const span = document.createElement("span");
span.textContent = thing[0];
setTextWithWrappedEmoji(span, thing[0]);
button.append(span);
span.classList.add("roleButtonStyle");
const role = this.guild.roleids.get(thing[1]) || this.guild.localuser.userMap.get(thing[1]);
+3
View File
@@ -2646,6 +2646,9 @@ span.instanceStatus {
object-fit: contain;
align-self: center;
}
span.emoji {
color: initial;
}
.userwrap {
display: flex;
align-items: baseline;
+3 -2
View File
@@ -17,7 +17,7 @@ import {Search} from "./search.js";
import {I18n} from "./i18n.js";
import {Hover} from "./hover.js";
import {Dialog, Float, Options} from "./settings.js";
import {createImg, removeAni, safeImg} from "./utils/utils.js";
import {createImg, removeAni, safeImg, setTextWithWrappedEmoji} from "./utils/utils.js";
import {Direct} from "./direct.js";
import {Permissions} from "./permissions.js";
import {Channel} from "./channel.js";
@@ -682,6 +682,7 @@ class User extends SnowFlake {
elms = new Set<WeakRef<HTMLElement>>();
subName(elm: HTMLElement) {
this.elms.add(new WeakRef(elm));
setTextWithWrappedEmoji(elm, this.name);
}
nameChange() {
this.getMembersSync().forEach((memb) => {
@@ -694,7 +695,7 @@ class User extends SnowFlake {
this.elms.delete(ref);
continue;
}
elm.textContent = this.name;
setTextWithWrappedEmoji(elm, this.name);
}
}
+29
View File
@@ -31,6 +31,35 @@ let instances:
}[]
| null = null;
await setTheme();
const emojiGraphemeRegex = /^(?:[0-9#*]\uFE0F?\u20E3|\p{Regional_Indicator}{2}|\p{Extended_Pictographic}(?:\uFE0F|\uFE0E)?[\u{1F3FB}-\u{1F3FF}]?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|\uFE0E)?[\u{1F3FB}-\u{1F3FF}]?)*?)$/u;
export function setTextWithWrappedEmoji(target: HTMLElement, name: string) {
target.textContent = "";
if (!("Segmenter" in Intl)) {
target.textContent = name;
return;
}
const segmenter = new Intl.Segmenter("und", {granularity: "grapheme"});
let textBuffer = "";
const flushTextBuffer = () => {
if (!textBuffer) return;
target.append(textBuffer);
textBuffer = "";
};
for (const {segment} of segmenter.segment(name)) {
if (emojiGraphemeRegex.test(segment)) {
flushTextBuffer();
const emoji = document.createElement("span");
emoji.classList.add("emoji");
emoji.textContent = segment;
target.append(emoji);
} else {
textBuffer += segment;
}
}
flushTextBuffer();
}
export async function setTheme(theme?: string) {
const prefs = await getPreferences();
document.body.className = (theme || prefs.theme) + "-theme";