Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
thororen1234 2026-05-05 13:55:22 -04:00
commit d7a841f1b3
No known key found for this signature in database
16 changed files with 129 additions and 294 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "equicord", "name": "equicord",
"private": "true", "private": "true",
"version": "1.14.11.0", "version": "1.14.12.0",
"description": "The other cutest Discord client mod", "description": "The other cutest Discord client mod",
"homepage": "https://github.com/Equicord/Equicord#readme", "homepage": "https://github.com/Equicord/Equicord#readme",
"bugs": { "bugs": {

View file

@ -17,6 +17,7 @@
*/ */
import ErrorBoundary from "@components/ErrorBoundary"; import ErrorBoundary from "@components/ErrorBoundary";
import { Logger } from "@utils/Logger";
import { JSX, ReactNode } from "react"; import { JSX, ReactNode } from "react";
export type MessageAccessoryFactory = (props: Record<string, any>) => ReactNode; export type MessageAccessoryFactory = (props: Record<string, any>) => ReactNode;
@ -46,23 +47,28 @@ export function _modifyAccessories(
elements: JSX.Element[], elements: JSX.Element[],
props: Record<string, any> props: Record<string, any>
) { ) {
for (const [key, accessory] of accessories.entries()) { try {
const res = ( for (const [key, accessory] of accessories.entries()) {
<ErrorBoundary noop message={`Failed to render ${key} Message Accessory`} key={key}> const res = (
<accessory.render {...props} /> <ErrorBoundary noop message={`Failed to render ${key} Message Accessory`} key={key}>
</ErrorBoundary> <accessory.render {...props} />
); </ErrorBoundary>
);
elements.splice( elements.splice(
accessory.position != null accessory.position != null
? accessory.position < 0 ? accessory.position < 0
? elements.length + accessory.position ? elements.length + accessory.position
: accessory.position : accessory.position
: elements.length, : elements.length,
0, 0,
res res
); );
}
return elements;
} catch (e) {
new Logger("MessageAccessories").error("Failed to modify message accessories", e);
return elements;
} }
return elements;
} }

View file

@ -28,7 +28,7 @@ export default definePlugin({
find: "#{intl::REMOVE_ATTACHMENT_BODY}", find: "#{intl::REMOVE_ATTACHMENT_BODY}",
replacement: { replacement: {
match: /children:(\[[^\]]{0,100}?this.renderSuppressConfirmModal[^\]]{0,100}?\])/, match: /children:(\[[^\]]{0,100}?this.renderSuppressConfirmModal[^\]]{0,100}?\])/,
replace: "children:Vencord.Api.MessageAccessories._modifyAccessories($1,this.props)", replace: "children:Vencord.Api.MessageAccessories._modifyAccessories($1,this?.props)",
}, },
}, },
], ],

View file

@ -49,7 +49,7 @@ export default definePlugin({
replacement: [ replacement: [
{ {
match: /(\.renderReactions\(\i\).+?className:)/, match: /(\.renderReactions\(\i\).+?className:)/,
replace: '$&(this.props?.channel?.nsfw || $self.settings.store.blurAllChannels ? "vc-nsfw-img ": "")+' replace: '$&(this?.props?.channel?.nsfw || $self.settings.store.blurAllChannels ? "vc-nsfw-img ": "")+'
} }
] ]
} }

View file

@ -139,7 +139,7 @@ export default definePlugin({
find: "renderConnectionStatus(){", find: "renderConnectionStatus(){",
replacement: { replacement: {
match: /(renderConnectionStatus\(\).{0,1000}?lineClamp:1,children:)(\i)(?=,|}\))/, match: /(renderConnectionStatus\(\).{0,1000}?lineClamp:1,children:)(\i)(?=,|}\))/,
replace: "$1[$2,$self.renderConnectionTimer(this.props?.channel?.id)]" replace: "$1[$2,$self.renderTimer({ channelId: this?.props?.channel?.id })]"
} }
} }
], ],
@ -270,11 +270,15 @@ export default definePlugin({
</ErrorBoundary>; </ErrorBoundary>;
}, },
ConnectionTimer({ channelId }: { channelId: string; }) { ConnectionTimer: ErrorBoundary.wrap(({ channelId }: { channelId: string; }) => {
const time = useTimer({ const time = useTimer({
deps: [channelId] deps: [channelId]
}); });
return <p style={{ margin: 0, fontFamily: "var(--font-code)" }}>{formatDurationMs(time, settings.store.format === "human")}</p>; return (
} <p style={{ margin: 0, fontFamily: "var(--font-code)" }}>
{formatDurationMs(time, settings.store.format === "human")}
</p>
);
}, { noop: true }),
}); });

View file

@ -94,7 +94,7 @@ export default definePlugin({
// https://regex101.com/r/07gpzP/1 // https://regex101.com/r/07gpzP/1
// ($1 renderHeaderContent=function { ... switch (x) ... case FAVORITES:return) ($2) ($3 case default: ... return r.jsx(($<searchComp>), {...props})) // ($1 renderHeaderContent=function { ... switch (x) ... case FAVORITES:return) ($2) ($3 case default: ... return r.jsx(($<searchComp>), {...props}))
match: /(renderHeaderContent\(\).{1,150}FAVORITES:return)(.{1,150});(case.{1,200}default:.{0,50}?return\(0,\i\.jsx\)\((?<searchComp>\i\.\i),)/, match: /(renderHeaderContent\(\).{1,150}FAVORITES:return)(.{1,150});(case.{1,200}default:.{0,50}?return\(0,\i\.jsx\)\((?<searchComp>\i\.\i),)/,
replace: "$1 this.state.resultType === 'Favorites' ? $self.renderSearchBar(this, $<searchComp>) : $2;$3" replace: "$1 this?.state?.resultType === 'Favorites' ? $self.renderSearchBar(this, $<searchComp>) : $2;$3"
}, },
{ {
// to persist filtered favorites when component re-renders. // to persist filtered favorites when component re-renders.

View file

@ -33,7 +33,7 @@ export default definePlugin({
find: ".handleImageLoad)", find: ".handleImageLoad)",
replacement: { replacement: {
match: /getSrc\(\i\)\{/, match: /getSrc\(\i\)\{/,
replace: "$&var _vcSrc=$self.getSrc(this.props,arguments[1]);if(_vcSrc)return _vcSrc;" replace: "$&var _vcSrc=$self.getSrc(this?.props,arguments[1]);if(_vcSrc)return _vcSrc;"
} }
} }
], ],

View file

@ -33,7 +33,7 @@ export default definePlugin({
find: "handleSelectGIF=", find: "handleSelectGIF=",
replacement: { replacement: {
match: /handleSelectGIF=(\i)=>\{/, match: /handleSelectGIF=(\i)=>\{/,
replace: "$&if (!this.props.className) return $self.handleSelect($1);" replace: "$&if (!this?.props?.className) return $self.handleSelect($1);"
} }
}], }],

View file

@ -1,46 +0,0 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2023 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
const settings = definePluginSettings({
inlineVideo: {
description: "Play videos without carousel modal",
type: OptionType.BOOLEAN,
default: true,
restartNeeded: true
}
});
export default definePlugin({
name: "NoMosaic",
authors: [Devs.AutumnVN],
description: "Removes Discord image mosaic",
tags: ["Media", "Appearance", "Chat"],
searchTerms: ["image", "mosaic", "media"],
settings,
patches: [
{
find: '"PLAINTEXT_PREVIEW":"OTHER"',
replacement: {
match: /"IMAGE"===\i\|\|"VIDEO"===\i\|\|"CLIP"===\i/,
replace: "false"
}
},
{
find: "renderAttachments(",
predicate: () => settings.store.inlineVideo,
replacement: {
match: /url:(\i)\.url\}\);return /,
replace: "$&$1.content_type?.startsWith('image/')&&"
}
},
]
});

View file

@ -30,7 +30,7 @@ export default definePlugin({
find: "hasThemeColors(){", find: "hasThemeColors(){",
replacement: { replacement: {
match: /get canUsePremiumProfileCustomization\(\){return /, match: /get canUsePremiumProfileCustomization\(\){return /,
replace: "$&$self.isCurrentUser(this.userId)&&" replace: "$&$self.isCurrentUser(this?.userId)&&"
} }
}, },
], ],

View file

@ -251,9 +251,6 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str
label={getIntlMessage("VIEW_AS_ROLE")} label={getIntlMessage("VIEW_AS_ROLE")}
icon={ViewAsRoleIcon} icon={ViewAsRoleIcon}
action={() => { action={() => {
const role = GuildRoleStore.getRole(guild.id, roleId);
if (!role) return;
onClose(); onClose();
FluxDispatcher.dispatch({ FluxDispatcher.dispatch({
type: "IMPERSONATE_UPDATE", type: "IMPERSONATE_UPDATE",

View file

@ -115,7 +115,7 @@ export default definePlugin({
{ {
// Override scrollToChannel to properly account for pinned channels // Override scrollToChannel to properly account for pinned channels
match: /(?<=scrollTo\(\{to:\i\}\):\(\i\+=)(\d+)\*\(.+?(?=,)/, match: /(?<=scrollTo\(\{to:\i\}\):\(\i\+=)(\d+)\*\(.+?(?=,)/,
replace: "$self.getScrollOffset(arguments[0],$1,this.props.padding,this.state.preRenderedChildren,$&)" replace: "$self.getScrollOffset(arguments[0],$1,this?.props?.padding,this?.state?.preRenderedChildren,$&)"
}, },
{ {
match: /(scrollToChannel\(\i\){.{1,300})(this\.props\.privateChannelIds)/, match: /(scrollToChannel\(\i\){.{1,300})(this\.props\.privateChannelIds)/,

View file

@ -151,7 +151,7 @@ export default definePlugin({
"renderInviteButton", "renderInviteButton",
].map(func => ({ ].map(func => ({
match: new RegExp(`(?<=${func}\\(\\){)`, "g"), // Global because Discord has multiple declarations of the same functions match: new RegExp(`(?<=${func}\\(\\){)`, "g"), // Global because Discord has multiple declarations of the same functions
replace: "if($self.isHiddenChannel(this.props.channel))return null;" replace: "if($self.isHiddenChannel(this?.props?.channel))return null;"
})) }))
] ]
}, },
@ -161,7 +161,7 @@ export default definePlugin({
// Render null instead of the buttons if the channel is hidden // Render null instead of the buttons if the channel is hidden
replacement: { replacement: {
match: /(?<=renderOpenChatButton(?:",|=)\(\)=>{)/, match: /(?<=renderOpenChatButton(?:",|=)\(\)=>{)/,
replace: "if($self.isHiddenChannel(this.props.channel))return null;" replace: "if($self.isHiddenChannel(this?.props?.channel))return null;"
} }
}, },
{ {
@ -268,11 +268,11 @@ export default definePlugin({
}, },
{ {
match: /(?<=renderSidebar\(\){)/, match: /(?<=renderSidebar\(\){)/,
replace: "if($self.isHiddenChannel(this.props.channel))return null;" replace: "if($self.isHiddenChannel(this?.props?.channel))return null;"
}, },
{ {
match: /(?<=renderChat\(\){)/, match: /(?<=renderChat\(\){)/,
replace: "if($self.isHiddenChannel(this.props.channel))return $self.HiddenChannelLockScreen(this.props.channel);" replace: "if($self.isHiddenChannel(this?.props?.channel))return $self.HiddenChannelLockScreen(this?.props?.channel);"
} }
] ]
}, },
@ -378,22 +378,22 @@ export default definePlugin({
{ {
// Render our HiddenChannelLockScreen component instead of the main voice channel component // Render our HiddenChannelLockScreen component instead of the main voice channel component
match: /renderContent\(\i\){.+?this\.renderVoiceChannelEffects.+?children:/, match: /renderContent\(\i\){.+?this\.renderVoiceChannelEffects.+?children:/,
replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?$self.HiddenChannelLockScreen(this.props.channel):" replace: "$&!this?.props?.inCall&&$self.isHiddenChannel(this?.props?.channel,true)?$self.HiddenChannelLockScreen(this?.props?.channel):"
}, },
{ {
// Disable gradients for the HiddenChannelLockScreen of voice channels // Disable gradients for the HiddenChannelLockScreen of voice channels
match: /renderContent\(\i\){.+?disableGradients:/, match: /renderContent\(\i\){.+?disableGradients:/,
replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)||" replace: "$&!this?.props?.inCall&&$self.isHiddenChannel(this?.props?.channel,true)||"
}, },
{ {
// Disable useless components for the HiddenChannelLockScreen of voice channels // Disable useless components for the HiddenChannelLockScreen of voice channels
match: /(?:{|,)render(?!Header|ExternalHeader).{0,30}?:/g, match: /(?:{|,)render(?!Header|ExternalHeader).{0,30}?:/g,
replace: "$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?()=>null:" replace: "$&!this?.props?.inCall&&$self.isHiddenChannel(this?.props?.channel,true)?()=>null:"
}, },
{ {
// Disable bad CSS class which mess up hidden voice channels styling // Disable bad CSS class which mess up hidden voice channels styling
match: /(?=\i\|\|\i!==\i\.\i\.FULL_SCREEN.{0,100}?this\._callContainerRef)/, match: /(?=\i\|\|\i!==\i\.\i\.FULL_SCREEN.{0,100}?this\._callContainerRef)/,
replace: '$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?"":' replace: '$&!this?.props?.inCall&&$self.isHiddenChannel(this?.props?.channel,true)?"":'
} }
] ]
}, },

View file

@ -23,7 +23,7 @@ export default definePlugin({
find: ".tabBarRef", find: ".tabBarRef",
replacement: { replacement: {
match: /style:this\.getStyle\(\),role:"tab"/, match: /style:this\.getStyle\(\),role:"tab"/,
replace: "$&,'data-tab-id':this.props.id" replace: "$&,'data-tab-id':this?.props?.id"
} }
}, },
@ -58,7 +58,7 @@ export default definePlugin({
], ],
getAvatarStyles(src: string | null) { getAvatarStyles(src: string | null) {
if (!src || src.startsWith("data:")) return {}; if (typeof src !== "string" || src.startsWith("data:")) return {};
return Object.fromEntries( return Object.fromEntries(
[128, 256, 512, 1024, 2048, 4096].map(size => [ [128, 256, 512, 1024, 2048, 4096].map(size => [

View file

@ -322,9 +322,9 @@ export function deeplLanguageToGoogleLanguage(language: string) {
// Generated using: // Generated using:
// curl https://translate.kagi.com/api/list-languages | jq 'map({(.language | ascii_downcase): .name}) | add | to_entries | sort_by(.value) | from_entries' // curl https://translate.kagi.com/api/list-languages | jq 'map({(.language | ascii_downcase): .name}) | add | to_entries | sort_by(.value) | from_entries'
// Add "auto": "Detect language", as kagi has no "language" for Detect Language, however anything not // Add "auto": "Detect language", as Kagi has no "language" for Detect Language, however anything not
// in the list will work as auto. Using "auto" will have this work using Google Translate defaults. // in the list will work as auto. Using "auto" will have this work using Google Translate defaults.
// Retrieved 2025.06.16 // Retrieved 2026-05-02. Meme languages and redundant entries removed.
export const KagiLanguages = { export const KagiLanguages = {
"auto": "Detect language", "auto": "Detect language",
"om": "(Afan)/Oromoor/Oriya", "om": "(Afan)/Oromoor/Oriya",
@ -338,19 +338,6 @@ export const KagiLanguages = {
"alz": "Alur", "alz": "Alur",
"am": "Amharic", "am": "Amharic",
"ar": "Arabic", "ar": "Arabic",
"ar_dz": "Arabic (Algeria)",
"ar_eg": "Arabic (Egypt)",
"ar_iq": "Arabic (Iraq)",
"ar_jo": "Arabic (Jordan)",
"ar_kw": "Arabic (Kuwait)",
"ar_lb": "Arabic (Lebanon)",
"ar_ly": "Arabic (Libya)",
"ar_ma": "Arabic (Morocco)",
"ar_qa": "Arabic (Qatar)",
"ar_sa": "Arabic (Saudi Arabia)",
"ar_sy": "Arabic (Syria)",
"ar_tn": "Arabic (Tunisia)",
"ar_ae": "Arabic (UAE)",
"an": "Aragonese", "an": "Aragonese",
"hy": "Armenian", "hy": "Armenian",
"as": "Assamese", "as": "Assamese",
@ -358,7 +345,7 @@ export const KagiLanguages = {
"ae": "Avestan", "ae": "Avestan",
"ava": "Awadhi", "ava": "Awadhi",
"ay": "Aymara", "ay": "Aymara",
"az": "Azeri", "az": "Azerbaijani",
"ban": "Balinese", "ban": "Balinese",
"bal": "Baluchi", "bal": "Baluchi",
"bm": "Bambara", "bm": "Bambara",
@ -366,11 +353,10 @@ export const KagiLanguages = {
"ba": "Bashkir", "ba": "Bashkir",
"eu": "Basque", "eu": "Basque",
"btk": "Batak", "btk": "Batak",
"bar": "Bavarian",
"be": "Belarusian", "be": "Belarusian",
"bem": "Bemba", "bem": "Bemba",
"bn": "Bengali", "bn": "Bengali",
"bn_bd": "Bengali (Bangladesh)",
"bn_in": "Bengali (India)",
"bew": "Betawi", "bew": "Betawi",
"bho": "Bhojpuri", "bho": "Bhojpuri",
"dz": "Bhutani", "dz": "Bhutani",
@ -390,11 +376,7 @@ export const KagiLanguages = {
"ce": "Chechen", "ce": "Chechen",
"chr": "Cherokee", "chr": "Cherokee",
"ny": "Chichewa", "ny": "Chichewa",
"zh": "Chinese",
"zh_hk": "Chinese (Hong Kong)",
"zh_mo": "Chinese (Macau)",
"zh_cn": "Chinese (Simplified)", "zh_cn": "Chinese (Simplified)",
"zh_sg": "Chinese (Singapore)",
"zh_tw": "Chinese (Traditional)", "zh_tw": "Chinese (Traditional)",
"cu": "Church Slavonic", "cu": "Church Slavonic",
"chk": "Chuukese", "chk": "Chuukese",
@ -404,65 +386,34 @@ export const KagiLanguages = {
"cr": "Cree", "cr": "Cree",
"crh": "Crimean Tatar", "crh": "Crimean Tatar",
"hr": "Croatian", "hr": "Croatian",
"hr_ba": "Croatian (Bosnia and Herzegovina)",
"hr_hr": "Croatian (Croatia)",
"cs": "Czech", "cs": "Czech",
"da": "Danish", "da": "Danish",
"din": "Dinka", "din": "Dinka",
"div": "Divehi", "div": "Divehi",
"dv": "Divehi",
"doi": "Dogri", "doi": "Dogri",
"dov": "Dombe", "dov": "Dombe",
"nl": "Dutch", "nl": "Dutch",
"nl_aw": "Dutch (Aruba)",
"nl_be": "Dutch (Belgium)",
"nl_cw": "Dutch (Curaçao)",
"nl_nl": "Dutch (Netherlands)",
"nl_sr": "Dutch (Suriname)",
"dyu": "Dyula", "dyu": "Dyula",
"elvish": "Elvish (Sindarin)",
"emoji": "Emoji Speak",
"en": "English",
"en_au": "English (Australia)",
"en_ca": "English (Canada)",
"en_in": "English (India)",
"en_ie": "English (Ireland)",
"en_nz": "English (New Zealand)",
"en_ph": "English (Philippines)",
"en_sg": "English (Singapore)",
"en_za": "English (South Africa)",
"en_gb": "English (UK)", "en_gb": "English (UK)",
"en_us": "English (US)", "en_us": "English (US)",
"eo": "Esperanto", "eo": "Esperanto",
"et": "Estonian", "et": "Estonian",
"ee": "Ewe", "ee": "Ewe",
"mk": "FYRO Macedonian",
"fo": "Faroese", "fo": "Faroese",
"fa": "Farsi",
"fj": "Fiji", "fj": "Fiji",
"fil": "Filipino", "fil": "Filipino",
"fi": "Finnish", "fi": "Finnish",
"fon": "Fon", "fon": "Fon",
"fr": "French", "fr": "French",
"fr_be": "French (Belgium)",
"fr_ca": "French (Canada)",
"fr_ci": "French (Côte d'Ivoire)",
"fr_fr": "French (France)",
"fr_sn": "French (Senegal)",
"fr_ch": "French (Switzerland)",
"fy": "Frisian", "fy": "Frisian",
"fur": "Friulian", "fur": "Friulian",
"ff": "Fulah", "ff": "Fulah",
"gaa": "Ga", "gaa": "Ga",
"gd": "Gaelic",
"gl": "Galician", "gl": "Galician",
"lg": "Ganda", "lg": "Ganda",
"ka": "Georgian", "ka": "Georgian",
"de": "German", "de": "German",
"de_at": "German (Austria)", "hac": "Gorani (Hawrami)",
"de_de": "German (Germany)",
"de_li": "German (Liechtenstein)",
"de_lu": "German (Luxembourg)",
"el": "Greek", "el": "Greek",
"kl": "Greenlandic", "kl": "Greenlandic",
"gn": "Guarani", "gn": "Guarani",
@ -474,8 +425,6 @@ export const KagiLanguages = {
"hz": "Herero", "hz": "Herero",
"hil": "Hiligaynon", "hil": "Hiligaynon",
"hi": "Hindi", "hi": "Hindi",
"hi_fj": "Hindi (Fiji)",
"hi_in": "Hindi (India)",
"ho": "Hiri Motu", "ho": "Hiri Motu",
"hu": "Hungarian", "hu": "Hungarian",
"hrx": "Hunsrik", "hrx": "Hunsrik",
@ -489,12 +438,8 @@ export const KagiLanguages = {
"ie": "Interlingue", "ie": "Interlingue",
"iu": "Inuktitut", "iu": "Inuktitut",
"ik": "Inupiak", "ik": "Inupiak",
"ga": "Irish", "ga": "Irish Gaelic",
"it": "Italian", "it": "Italian",
"it_it": "Italian (Italy)",
"it_sm": "Italian (San Marino)",
"it_ch": "Italian (Switzerland)",
"it_va": "Italian (Vatican City)",
"jam": "Jamaican Patois", "jam": "Jamaican Patois",
"ja": "Japanese", "ja": "Japanese",
"jv": "Javanese", "jv": "Javanese",
@ -509,16 +454,14 @@ export const KagiLanguages = {
"ky": "Kirghiz", "ky": "Kirghiz",
"rn": "Kirundi", "rn": "Kirundi",
"ktu": "Kituba", "ktu": "Kituba",
"klingon": "Klingon",
"kv": "Komi", "kv": "Komi",
"kg": "Kongo", "kg": "Kongo",
"kok": "Konkani", "kok": "Konkani",
"ko": "Korean", "ko": "Korean",
"ko_kp": "Korean (North Korea)",
"ko_kr": "Korean (South Korea)",
"kj": "Kuanyama", "kj": "Kuanyama",
"ku": "Kurdish", "ku": "Kurdish (Kurmanji)",
"ckb": "Kurdish (Sorani)", "ckb": "Kurdish (Sorani)",
"sdh": "Kurdish (Xwarin)",
"lo": "Laothian", "lo": "Laothian",
"ltg": "Latgalian", "ltg": "Latgalian",
"la": "Latin", "la": "Latin",
@ -532,26 +475,22 @@ export const KagiLanguages = {
"lu": "Luba_Katanga", "lu": "Luba_Katanga",
"luo": "Luo", "luo": "Luo",
"lb": "Luxembourgish", "lb": "Luxembourgish",
"mk": "Macedonian",
"mad": "Madurese", "mad": "Madurese",
"mai": "Maithili", "mai": "Maithili",
"mak": "Makassar", "mak": "Makassar",
"mg": "Malagasy", "mg": "Malagasy",
"ms": "Malay", "ms": "Malay",
"ms_bn": "Malay (Brunei Darussalam)",
"ms_id": "Malay (Indonesia)",
"ms_arab": "Malay (Jawi)",
"ms_my": "Malay (Malaysia)",
"ms_sg": "Malay (Singapore)",
"ml": "Malayalam", "ml": "Malayalam",
"mt": "Maltese", "mt": "Maltese",
"gv": "Manx", "gv": "Manx Gaelic",
"mi": "Maori", "mi": "Maori",
"mr": "Marathi", "mr": "Marathi",
"mh": "Marshallese", "mh": "Marshallese",
"mwr": "Marwadi", "mwr": "Marwadi",
"middle_english": "Middle English",
"mo": "Moldavian", "mo": "Moldavian",
"mn": "Mongolian", "mn": "Mongolian",
"cnr": "Montenegrin",
"nqo": "NKo", "nqo": "NKo",
"nhe": "Nahuatl", "nhe": "Nahuatl",
"na": "Nauru", "na": "Nauru",
@ -561,7 +500,9 @@ export const KagiLanguages = {
"new": "Nepalbhasa", "new": "Nepalbhasa",
"ne": "Nepali", "ne": "Nepali",
"nd": "North Ndebele", "nd": "North Ndebele",
"se": "Northern Sami",
"ns": "Northern Sotho", "ns": "Northern Sotho",
"no": "Norwegian",
"nb": "Norwegian (Bokmål)", "nb": "Norwegian (Bokmål)",
"nn": "Norwegian (Nynorsk)", "nn": "Norwegian (Nynorsk)",
"nus": "Nuer", "nus": "Nuer",
@ -573,99 +514,54 @@ export const KagiLanguages = {
"pag": "Pangasinan", "pag": "Pangasinan",
"pap": "Papiamento", "pap": "Papiamento",
"ps": "Pashto/Pushto", "ps": "Pashto/Pushto",
"per": "Persian", "fa": "Persian",
"fa_af": "Persian (Afghanistan)",
"fa_ir": "Persian (Iran)",
"fa_tj": "Persian (Tajikistan)",
"pirate": "Pirate Speak",
"pl": "Polish", "pl": "Polish",
"pt": "Portuguese",
"pt_ao": "Portuguese (Angola)",
"pt_br": "Portuguese (Brazil)", "pt_br": "Portuguese (Brazil)",
"pt_cv": "Portuguese (Cape Verde)",
"pt_mz": "Portuguese (Mozambique)",
"pt_pt": "Portuguese (Portugal)", "pt_pt": "Portuguese (Portugal)",
"pa": "Punjabi", "pa": "Punjabi",
"qu": "Quechua", "qu": "Quechua",
"qu_bo": "Quechua (Bolivia)",
"qu_ec": "Quechua (Ecuador)",
"qu_pe": "Quechua (Peru)",
"kek": "Qʼeqchiʼ", "kek": "Qʼeqchiʼ",
"rm": "Rhaeto_Romanic", "rm": "Rhaeto_Romanic",
"rom": "Romani", "rom": "Romani",
"ro": "Romanian", "ro": "Romanian",
"ru": "Russian", "ru": "Russian",
"ru_by": "Russian (Belarus)",
"ru_kz": "Russian (Kazakhstan)",
"ru_kg": "Russian (Kyrgyzstan)",
"ru_ru": "Russian (Russia)",
"se": "Sami",
"se_fi": "Sami (Finland)",
"se_no": "Sami (Norway)",
"se_se": "Sami (Sweden)",
"sm": "Samoan", "sm": "Samoan",
"sg": "Sangro", "sg": "Sangro",
"sa": "Sanskrit", "sa": "Sanskrit",
"sat": "Santali", "sat": "Santali",
"sc": "Sardinian", "sc": "Sardinian",
"sco": "Scots",
"gd": "Scottish Gaelic",
"sr": "Serbian", "sr": "Serbian",
"sr_ba": "Serbian (Bosnia and Herzegovina)",
"sr_sp": "Serbian (Serbia and Montenegro)",
"sh": "Serbo_Croatian", "sh": "Serbo_Croatian",
"st": "Sesotho", "st": "Sesotho",
"seto": "Seto",
"shn": "Shan", "shn": "Shan",
"sn": "Shona", "sn": "Shona",
"ii": "Sichuan Yi", "ii": "Sichuan Yi",
"scn": "Sicilian", "scn": "Sicilian",
"szl": "Silesian", "szl": "Silesian",
"sd": "Sindhi", "sd": "Sindhi",
"si": "Singhalese", "si": "Sinhalese",
"ss": "Siswati", "ss": "Siswati",
"sk": "Slovak", "sk": "Slovak",
"sl": "Slovenian", "sl": "Slovenian",
"so": "Somali", "so": "Somali",
"sb": "Sorbian", "sb": "Sorbian",
"nr": "South Ndebele", "nr": "South Ndebele",
"sma": "Southern Sami",
"es": "Spanish", "es": "Spanish",
"es_ar": "Spanish (Argentina)",
"es_bo": "Spanish (Bolivia)",
"es_cl": "Spanish (Chile)",
"es_co": "Spanish (Colombia)",
"es_cr": "Spanish (Costa Rica)",
"es_cu": "Spanish (Cuba)",
"es_do": "Spanish (Dominican Republic)",
"es_ec": "Spanish (Ecuador)",
"es_sv": "Spanish (El Salvador)",
"es_gq": "Spanish (Equatorial Guinea)",
"es_gt": "Spanish (Guatemala)",
"es_hn": "Spanish (Honduras)",
"es_mx": "Spanish (Mexico)",
"es_ni": "Spanish (Nicaragua)",
"es_pa": "Spanish (Panama)",
"es_py": "Spanish (Paraguay)",
"es_pe": "Spanish (Peru)",
"es_pr": "Spanish (Puerto Rico)",
"es_es": "Spanish (Spain)",
"es_uy": "Spanish (Uruguay)",
"es_ve": "Spanish (Venezuela)",
"su": "Sundanese", "su": "Sundanese",
"sus": "Susu", "sus": "Susu",
"sx": "Sutu", "sx": "Sutu",
"sw": "Swahili", "sw": "Swahili",
"sv": "Swedish", "sv": "Swedish",
"sv_fi": "Swedish (Finland)",
"sv_se": "Swedish (Sweden)",
"gsw": "Swiss German", "gsw": "Swiss German",
"de_ch": "Swiss High German",
"syr": "Syriac", "syr": "Syriac",
"tl": "Tagalog", "tl": "Tagalog",
"ty": "Tahitian", "ty": "Tahitian",
"tg": "Tajik", "tg": "Tajik",
"ta": "Tamil", "ta": "Tamil",
"ta_in": "Tamil (India)",
"ta_my": "Tamil (Malaysia)",
"ta_sg": "Tamil (Singapore)",
"ta_lk": "Tamil (Sri Lanka)",
"tt": "Tatar", "tt": "Tatar",
"te": "Telugu", "te": "Telugu",
"tet": "Tetum", "tet": "Tetum",
@ -679,8 +575,6 @@ export const KagiLanguages = {
"tn": "Tswana", "tn": "Tswana",
"tum": "Tumbuka", "tum": "Tumbuka",
"tr": "Turkish", "tr": "Turkish",
"tr_cy": "Turkish (Cyprus)",
"tr_tr": "Turkish (Turkey)",
"tk": "Turkmen", "tk": "Turkmen",
"tyv": "Tuvan", "tyv": "Tuvan",
"tw": "Twi", "tw": "Twi",
@ -688,13 +582,12 @@ export const KagiLanguages = {
"ug": "Uighur", "ug": "Uighur",
"uk": "Ukrainian", "uk": "Ukrainian",
"ur": "Urdu", "ur": "Urdu",
"ur_in": "Urdu (India)",
"ur_pk": "Urdu (Pakistan)",
"uz": "Uzbek", "uz": "Uzbek",
"ve": "Venda", "ve": "Venda",
"vec": "Venetian", "vec": "Venetian",
"vi": "Vietnamese", "vi": "Vietnamese",
"vo": "Volapuk", "vo": "Volapuk",
"vro": "Võro",
"wa": "Walloon", "wa": "Walloon",
"war": "Waray", "war": "Waray",
"cy": "Welsh", "cy": "Welsh",
@ -705,6 +598,7 @@ export const KagiLanguages = {
"yo": "Yoruba", "yo": "Yoruba",
"yua": "Yucatec Maya", "yua": "Yucatec Maya",
"zap": "Zapotec", "zap": "Zapotec",
"diq": "Zazaki",
"za": "Zhuang", "za": "Zhuang",
"zu": "Zulu" "zu": "Zulu"
} as const; } as const;

View file

@ -26,6 +26,17 @@ import definePlugin, { OptionType } from "@utils/types";
import { CustomEmoji, Message, ReactionEmoji, User } from "@vencord/discord-types"; import { CustomEmoji, Message, ReactionEmoji, User } from "@vencord/discord-types";
import { ChannelStore, Constants, FluxDispatcher, React, RestAPI, useEffect, useLayoutEffect, UserStore, UserSummaryItem } from "@webpack/common"; import { ChannelStore, Constants, FluxDispatcher, React, RestAPI, useEffect, useLayoutEffect, UserStore, UserSummaryItem } from "@webpack/common";
interface ReactionCacheEntry {
fetched: boolean;
users: Map<string, User>;
}
interface ReactionProps {
message: Message;
emoji: CustomEmoji;
type: number;
}
let Scroll: any = null; let Scroll: any = null;
const queue = new Queue(); const queue = new Queue();
let reactions: Record<string, ReactionCacheEntry> = {}; let reactions: Record<string, ReactionCacheEntry> = {};
@ -76,6 +87,46 @@ function handleClickAvatar(event: React.UIEvent<HTMLElement, Event>) {
event.stopPropagation(); event.stopPropagation();
} }
function ReactionUsers({ message, emoji, type }: ReactionProps) {
const forceUpdate = useForceUpdater();
useLayoutEffect(() => { // bc need to prevent autoscrolling
if (Scroll?.scrollCounter > 0) {
Scroll.setAutomaticAnchor(null);
}
});
useEffect(() => {
const cb = (e: any) => {
if (e?.messageId === message.id)
forceUpdate();
};
FluxDispatcher.subscribe("MESSAGE_REACTION_ADD_USERS", cb);
return () => FluxDispatcher.unsubscribe("MESSAGE_REACTION_ADD_USERS", cb);
}, [message.id, forceUpdate]);
const reactions = getReactionsWithQueue(message, emoji, type);
const users = Array.from(reactions, ([id]) => UserStore.getUser(id)).filter(Boolean);
return (
<div
style={{ marginLeft: "0.5em", transform: "scale(0.9)" }}
>
<div onClick={handleClickAvatar} onKeyDown={handleClickAvatar}>
<UserSummaryItem
users={users}
guildId={ChannelStore.getChannel(message.channel_id)?.guild_id}
renderIcon={false}
max={5}
showDefaultAvatarsForNullUsers
showUserPopout
/>
</div>
</div>
);
}
const settings = definePluginSettings({ const settings = definePluginSettings({
avatarClick: { avatarClick: {
description: "Toggle clicking avatars in reactions", description: "Toggle clicking avatars in reactions",
@ -96,8 +147,8 @@ export default definePlugin({
{ {
find: ",reactionRef:", find: ",reactionRef:",
replacement: { replacement: {
match: /\(0,\i\.jsx\)\(\i\.\i,\{className:\i\.reactionCount,.{0,60}\}\),/, match: /(\i)\?null:\(0,\i\.jsx\)\(\i\.\i,{className:\i\.reactionCount,.*?}\),(?<=(emoji:\i,message:\i,type:\i).+?)/,
replace: "$&$self.renderUsers(arguments[0])," replace: "$&$1?null:$self.renderUsers({$2}),"
} }
}, },
{ {
@ -117,88 +168,17 @@ export default definePlugin({
} }
], ],
renderUsers: ErrorBoundary.wrap((props: ReactionProps) => {
return props.message.reactions.length > 10
? null
: <ReactionUsers {...props} />;
}, { noop: true }),
setScrollObj(scroll: any) { setScrollObj(scroll: any) {
Scroll = scroll; Scroll = scroll;
}, },
renderUsers(props: RootObject) {
if (!props?.message || props.hideCount) return null;
return props.message.reactions.length > 10 ? null : (
<ErrorBoundary noop>
<this.UsersComponent {...props} />
</ErrorBoundary>
);
},
UsersComponent({ message, emoji, type }: RootObject) {
const forceUpdate = useForceUpdater();
useLayoutEffect(() => { // bc need to prevent autoscrolling
if (Scroll?.scrollCounter > 0) {
Scroll.setAutomaticAnchor(null);
}
});
useEffect(() => {
const cb = (e: any) => {
if (e?.messageId === message.id)
forceUpdate();
};
FluxDispatcher.subscribe("MESSAGE_REACTION_ADD_USERS", cb);
return () => FluxDispatcher.unsubscribe("MESSAGE_REACTION_ADD_USERS", cb);
}, [message.id, forceUpdate]);
const reactions = getReactionsWithQueue(message, emoji, type);
const users = Array.from(reactions, ([id]) => UserStore.getUser(id)).filter(Boolean);
return (
<div
style={{ marginLeft: "0.5em", transform: "scale(0.9)" }}
>
<div
onClick={handleClickAvatar}
onKeyDown={handleClickAvatar}
style={settings.store.avatarClick ? {} : { pointerEvents: "none" }}
>
<UserSummaryItem
users={users}
guildId={ChannelStore.getChannel(message.channel_id)?.guild_id}
renderIcon={false}
max={5}
showDefaultAvatarsForNullUsers
showUserPopout
/>
</div>
</div>
);
},
set reactions(value: any) { set reactions(value: any) {
reactions = value; reactions = value;
} }
}); });
interface ReactionCacheEntry {
fetched: boolean;
users: Map<string, User>;
}
interface RootObject {
message: Message;
readOnly: boolean;
isLurking: boolean;
isPendingMember: boolean;
useChatFontScaling: boolean;
emoji: CustomEmoji;
count: number;
burst_user_ids: any[];
burst_count: number;
burst_colors: any[];
burst_me: boolean;
me: boolean;
type: number;
hideCount: boolean;
hideEmoji: boolean;
remainingBurstCurrency: number;
}