mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-09 17:36:23 +00:00
Merge branch 'dev' into main
This commit is contained in:
commit
601c254a1d
137 changed files with 1122 additions and 1013 deletions
|
@ -5,6 +5,7 @@
|
|||
// @author Vendicated (https://github.com/Vendicated)
|
||||
// @namespace https://github.com/Vendicated/Vencord
|
||||
// @supportURL https://github.com/Vendicated/Vencord
|
||||
// @icon https://raw.githubusercontent.com/Vendicated/Vencord/refs/heads/main/browser/icon.png
|
||||
// @license GPL-3.0
|
||||
// @match *://*.discord.com/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "vencord",
|
||||
"private": "true",
|
||||
"version": "1.10.3",
|
||||
"version": "1.10.7",
|
||||
"description": "The cutest Discord client mod",
|
||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||
"bugs": {
|
||||
|
@ -35,6 +35,7 @@
|
|||
"testTsc": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@intrnl/xxhash64": "^0.1.2",
|
||||
"@sapphi-red/web-noise-suppressor": "0.3.5",
|
||||
"@vap/core": "0.0.12",
|
||||
"@vap/shiki": "0.10.5",
|
||||
|
|
|
@ -16,6 +16,9 @@ importers:
|
|||
|
||||
.:
|
||||
dependencies:
|
||||
'@intrnl/xxhash64':
|
||||
specifier: ^0.1.2
|
||||
version: 0.1.2
|
||||
'@sapphi-red/web-noise-suppressor':
|
||||
specifier: 0.3.5
|
||||
version: 0.3.5
|
||||
|
@ -537,6 +540,9 @@ packages:
|
|||
resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
|
||||
engines: {node: '>=18.18'}
|
||||
|
||||
'@intrnl/xxhash64@0.1.2':
|
||||
resolution: {integrity: sha512-1+lx7j99fdph+uy3EnjQyr39KQZ7LP56+aWOr6finJWpgYpvb7XrhFUqDwnEk/wpPC98nCjAT6RulpW3crWjlg==}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.5':
|
||||
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
@ -2939,6 +2945,8 @@ snapshots:
|
|||
|
||||
'@humanwhocodes/retry@0.3.0': {}
|
||||
|
||||
'@intrnl/xxhash64@0.1.2': {}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.5':
|
||||
dependencies:
|
||||
'@jridgewell/set-array': 1.2.1
|
||||
|
|
|
@ -225,7 +225,7 @@ page.on("console", async e => {
|
|||
plugin,
|
||||
type,
|
||||
id,
|
||||
match: regex.replace(/\[A-Za-z_\$\]\[\\w\$\]\*/g, "\\i"),
|
||||
match: regex.replace(/\(\?:\[A-Za-z_\$\]\[\\w\$\]\*\)/g, "\\i"),
|
||||
error: await maybeGetError(e.args()[3])
|
||||
});
|
||||
|
||||
|
|
|
@ -18,9 +18,8 @@
|
|||
|
||||
import "./iconStyles.css";
|
||||
|
||||
import { getTheme, Theme } from "@utils/discord";
|
||||
import { getIntlMessage, getTheme, Theme } from "@utils/discord";
|
||||
import { classes } from "@utils/misc";
|
||||
import { i18n } from "@webpack/common";
|
||||
import type { PropsWithChildren } from "react";
|
||||
|
||||
interface BaseIconProps extends IconProps {
|
||||
|
@ -133,7 +132,7 @@ export function InfoIcon(props: IconProps) {
|
|||
export function OwnerCrownIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
aria-label={i18n.Messages.GUILD_OWNER}
|
||||
aria-label={getIntlMessage("GUILD_OWNER")}
|
||||
{...props}
|
||||
className={classes(props.className, "vc-owner-crown-icon")}
|
||||
role="img"
|
||||
|
|
|
@ -247,7 +247,7 @@ function FullPatchInput({ setFind, setParsedFind, setMatch, setReplacement }: Fu
|
|||
}
|
||||
|
||||
try {
|
||||
const parsed = (0, eval)(`(${fullPatch})`) as Patch;
|
||||
const parsed = (0, eval)(`([${fullPatch}][0])`) as Patch;
|
||||
|
||||
if (!parsed.find) throw new Error("No 'find' field");
|
||||
if (!parsed.replacement) throw new Error("No 'replacement' field");
|
||||
|
|
|
@ -27,13 +27,16 @@ export async function loadLazyChunks() {
|
|||
|
||||
const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("?[^)]+?"?\)[^\]]*?)(?:\]\))?)\.then\(\i\.bind\(\i,"?([^)]+?)"?\)\)/g);
|
||||
|
||||
let foundCssDebuggingLoad = false;
|
||||
|
||||
async function searchAndLoadLazyChunks(factoryCode: string) {
|
||||
// Workaround to avoid loading the CSS debugging chunk which turns the app pink
|
||||
const hasCssDebuggingLoad = foundCssDebuggingLoad ? false : (foundCssDebuggingLoad = factoryCode.includes(".cssDebuggingEnabled&&"));
|
||||
|
||||
const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
|
||||
const validChunkGroups = new Set<[chunkIds: number[], entryPoint: number]>();
|
||||
|
||||
// Workaround for a chunk that depends on the ChannelMessage component but may be be force loaded before
|
||||
// the chunk containing the component
|
||||
const shouldForceDefer = factoryCode.includes(".Messages.GUILD_FEED_UNFEATURE_BUTTON_TEXT");
|
||||
const shouldForceDefer = false;
|
||||
|
||||
await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIds, entryPoint]) => {
|
||||
const chunkIds = rawChunkIds ? Array.from(rawChunkIds.matchAll(Webpack.ChunkIdsRegex)).map(m => Number(m[1])) : [];
|
||||
|
@ -45,6 +48,16 @@ export async function loadLazyChunks() {
|
|||
let invalidChunkGroup = false;
|
||||
|
||||
for (const id of chunkIds) {
|
||||
if (hasCssDebuggingLoad) {
|
||||
if (chunkIds.length > 1) {
|
||||
throw new Error("Found multiple chunks in factory that loads the CSS debugging chunk");
|
||||
}
|
||||
|
||||
invalidChunks.add(id);
|
||||
invalidChunkGroup = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wreq.u(id) == null || wreq.u(id) === "undefined.js") continue;
|
||||
|
||||
const isWorkerAsset = await fetch(wreq.p + wreq.u(id))
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
import { onceDefined } from "@shared/onceDefined";
|
||||
import electron, { app, BrowserWindowConstructorOptions, Menu } from "electron";
|
||||
import electron, { app, BrowserWindowConstructorOptions, Menu, nativeTheme } from "electron";
|
||||
import { dirname, join } from "path";
|
||||
|
||||
import { initIpc } from "./ipcMain";
|
||||
|
@ -100,6 +100,19 @@ if (!IS_VANILLA) {
|
|||
|
||||
super(options);
|
||||
initIpc(this);
|
||||
|
||||
// Workaround for https://github.com/electron/electron/issues/43367. Vesktop also has its own workaround
|
||||
// @TODO: Remove this when the issue is fixed
|
||||
if (IS_DISCORD_DESKTOP) {
|
||||
this.webContents.on("devtools-opened", () => {
|
||||
if (!nativeTheme.shouldUseDarkColors) return;
|
||||
|
||||
nativeTheme.themeSource = "light";
|
||||
setTimeout(() => {
|
||||
nativeTheme.themeSource = "dark";
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
} else super(options);
|
||||
}
|
||||
}
|
||||
|
|
24
src/plugins/_api/dynamicImageModalApi.ts
Normal file
24
src/plugins/_api/dynamicImageModalApi.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
|
||||
export default definePlugin({
|
||||
name: "DynamicImageModalAPI",
|
||||
authors: [Devs.sadan, Devs.Nuckyz],
|
||||
description: "Allows you to omit either width or height when opening an image modal",
|
||||
patches: [
|
||||
{
|
||||
find: "SCALE_DOWN:",
|
||||
replacement: {
|
||||
match: /!\(null==(\i)\|\|0===\i\|\|null==(\i)\|\|0===\i\)/,
|
||||
replace: (_, width, height) => `!((null == ${width} || 0 === ${width}) && (null == ${height} || 0 === ${height}))`
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
|
@ -31,7 +31,7 @@ export default definePlugin({
|
|||
match: /let\{[^}]*lostPermissionTooltipText:\i[^}]*\}=(\i),/,
|
||||
replace: "$&vencordProps=$1,"
|
||||
}, {
|
||||
match: /\.Messages\.GUILD_OWNER(?=.+?decorators:(\i)\(\)).+?\1=?\(\)=>.+?children:\[/,
|
||||
match: /#{intl::GUILD_OWNER}(?=.+?decorators:(\i)\(\)).+?\1=?\(\)=>.+?children:\[/,
|
||||
replace: "$&...(typeof vencordProps=='undefined'?[]:Vencord.Api.MemberListDecorators.__getDecorators(vencordProps)),"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -25,7 +25,7 @@ export default definePlugin({
|
|||
authors: [Devs.Cyn],
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.REMOVE_ATTACHMENT_BODY",
|
||||
find: "#{intl::REMOVE_ATTACHMENT_BODY}",
|
||||
replacement: {
|
||||
match: /(?<=.container\)?,children:)(\[.+?\])/,
|
||||
replace: "Vencord.Api.MessageAccessories._modifyAccessories($1,this.props)",
|
||||
|
|
|
@ -27,7 +27,7 @@ export default definePlugin({
|
|||
{
|
||||
find: '"Message Username"',
|
||||
replacement: {
|
||||
match: /\.Messages\.GUILD_COMMUNICATION_DISABLED_BOTTOM_SHEET_TITLE.+?}\),\i(?=\])/,
|
||||
match: /#{intl::GUILD_COMMUNICATION_DISABLED_BOTTOM_SHEET_TITLE}.+?}\),\i(?=\])/,
|
||||
replace: "$&,...Vencord.Api.MessageDecorations.__addDecorationsToMessage(arguments[0])"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ export default definePlugin({
|
|||
authors: [Devs.Arjix, Devs.hunt, Devs.Ven],
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.EDIT_TEXTAREA_HELP",
|
||||
find: "#{intl::EDIT_TEXTAREA_HELP}",
|
||||
replacement: {
|
||||
match: /(?<=,channel:\i\}\)\.then\().+?(?=return \i\.content!==this\.props\.message\.content&&\i\((.+?)\))/,
|
||||
replace: (match, args) => "" +
|
||||
|
|
|
@ -24,9 +24,9 @@ export default definePlugin({
|
|||
description: "API to add buttons to message popovers.",
|
||||
authors: [Devs.KingFish, Devs.Ven, Devs.Nuckyz],
|
||||
patches: [{
|
||||
find: "Messages.MESSAGE_UTILITIES_A11Y_LABEL",
|
||||
find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}",
|
||||
replacement: {
|
||||
match: /\.jsx\)\((\i\.\i),\{label:\i\.\i\.Messages\.MESSAGE_ACTION_REPLY.{0,200}?"reply-self".{0,50}?\}\):null(?=,.+?message:(\i))/,
|
||||
match: /\.jsx\)\((\i\.\i),\{label:\i\.\i\.string\(\i\.\i#{intl::MESSAGE_ACTION_REPLY}.{0,200}?"reply-self".{0,50}?\}\):null(?=,.+?message:(\i))/,
|
||||
replace: "$&,Vencord.Api.MessagePopover._buildPopoverElements($1,$2)"
|
||||
}
|
||||
}],
|
||||
|
|
|
@ -33,8 +33,8 @@ export default definePlugin({
|
|||
replace: "if(Vencord.Api.Notices.currentNotice)return false;$&"
|
||||
},
|
||||
{
|
||||
match: /(?<=function (\i)\(\i\){)return null!=(\i)(?=.*NOTICE_DISMISS:\1)/,
|
||||
replace: "if($2.id==\"VencordNotice\")return($2=null,Vencord.Api.Notices.nextNotice(),true);$&"
|
||||
match: /(?<=,NOTICE_DISMISS:function\(\i\){)return null!=(\i)/,
|
||||
replace: "if($1.id==\"VencordNotice\")return($1=null,Vencord.Api.Notices.nextNotice(),true);$&"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -25,16 +25,16 @@ export default definePlugin({
|
|||
description: "Api required for plugins that modify the server list",
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.DISCODO_DISABLED",
|
||||
find: "#{intl::DISCODO_DISABLED}",
|
||||
replacement: {
|
||||
match: /(?<=Messages\.DISCODO_DISABLED.+?return)(\(.{0,75}?tutorialContainer.+?}\))(?=}function)/,
|
||||
match: /(?<=#{intl::DISCODO_DISABLED}.+?return)(\(.{0,75}?tutorialContainer.+?}\))(?=}function)/,
|
||||
replace: "[$1].concat(Vencord.Api.ServerList.renderAll(Vencord.Api.ServerList.ServerListRenderPosition.Above))"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "Messages.SERVERS,children",
|
||||
find: "#{intl::SERVERS}),children",
|
||||
replacement: {
|
||||
match: /(?<=Messages\.SERVERS,children:)\i\.map\(\i\)/,
|
||||
match: /(?<=#{intl::SERVERS}\),children:)\i\.map\(\i\)/,
|
||||
replace: "Vencord.Api.ServerList.renderAll(Vencord.Api.ServerList.ServerListRenderPosition.In).concat($&)"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,15 +59,7 @@ export default definePlugin({
|
|||
replace: "$&return;"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
find: ".installedLogHooks)",
|
||||
replacement: {
|
||||
// if getDebugLogging() returns false, the hooks don't get installed.
|
||||
match: "getDebugLogging(){",
|
||||
replace: "getDebugLogging(){return false;"
|
||||
}
|
||||
},
|
||||
}
|
||||
],
|
||||
|
||||
startAt: StartAt.Init,
|
||||
|
|
|
@ -25,8 +25,9 @@ import ThemesTab from "@components/VencordSettings/ThemesTab";
|
|||
import UpdaterTab from "@components/VencordSettings/UpdaterTab";
|
||||
import VencordTab from "@components/VencordSettings/VencordTab";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { i18n, React } from "@webpack/common";
|
||||
import { React } from "@webpack/common";
|
||||
|
||||
import gitHash from "~git-hash";
|
||||
|
||||
|
@ -57,20 +58,20 @@ export default definePlugin({
|
|||
]
|
||||
},
|
||||
{
|
||||
find: "Messages.ACTIVITY_SETTINGS",
|
||||
find: ".SEARCH_NO_RESULTS&&0===",
|
||||
replacement: [
|
||||
{
|
||||
match: /(?<=section:(.{0,50})\.DIVIDER\}\))([,;])(?=.{0,200}(\i)\.push.{0,100}label:(\i)\.header)/,
|
||||
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
|
||||
},
|
||||
{
|
||||
match: /({(?=.+?function (\i).{0,120}(\i)=\i\.useMemo.{0,60}return \i\.useMemo\(\(\)=>\i\(\3).+?function\(\){return )\2(?=})/,
|
||||
match: /({(?=.+?function (\i).{0,160}(\i)=\i\.useMemo.{0,140}return \i\.useMemo\(\(\)=>\i\(\3).+?function\(\){return )\2(?=})/,
|
||||
replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL",
|
||||
find: "#{intl::USER_SETTINGS_ACTIONS_MENU_LABEL}",
|
||||
replacement: {
|
||||
match: /(?<=function\((\i),\i\)\{)(?=let \i=Object.values\(\i.\i\).*?(\i\.\i)\.open\()/,
|
||||
replace: "$2.open($1);return;"
|
||||
|
@ -148,13 +149,18 @@ export default definePlugin({
|
|||
|
||||
if (!header) return;
|
||||
|
||||
const names = {
|
||||
top: i18n.Messages.USER_SETTINGS,
|
||||
aboveNitro: i18n.Messages.BILLING_SETTINGS,
|
||||
belowNitro: i18n.Messages.APP_SETTINGS,
|
||||
aboveActivity: i18n.Messages.ACTIVITY_SETTINGS
|
||||
};
|
||||
return header === names[settingsLocation];
|
||||
try {
|
||||
const names = {
|
||||
top: getIntlMessage("USER_SETTINGS"),
|
||||
aboveNitro: getIntlMessage("BILLING_SETTINGS"),
|
||||
belowNitro: getIntlMessage("APP_SETTINGS"),
|
||||
aboveActivity: getIntlMessage("ACTIVITY_SETTINGS")
|
||||
};
|
||||
|
||||
return header === names[settingsLocation];
|
||||
} catch {
|
||||
return firstChild === "PREMIUM";
|
||||
}
|
||||
},
|
||||
|
||||
patchedSettings: new WeakSet(),
|
||||
|
@ -197,7 +203,7 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
get electronVersion() {
|
||||
return VencordNative.native.getVersions().electron || window.armcord?.electron || null;
|
||||
return VencordNative.native.getVersions().electron || window.legcord?.electron || null;
|
||||
},
|
||||
|
||||
get chromiumVersion() {
|
||||
|
|
|
@ -77,7 +77,7 @@ async function generateDebugInfoMessage() {
|
|||
const client = (() => {
|
||||
if (IS_DISCORD_DESKTOP) return `Discord Desktop v${DiscordNative.app.getVersion()}`;
|
||||
if (IS_VESKTOP) return `Vesktop v${VesktopNative.app.getVersion()}`;
|
||||
if ("armcord" in window) return `ArmCord v${window.armcord.version}`;
|
||||
if ("legcord" in window) return `Legcord v${window.legcord.version}`;
|
||||
|
||||
// @ts-expect-error
|
||||
const name = typeof unsafeWindow !== "undefined" ? "UserScript" : "Web";
|
||||
|
@ -147,10 +147,10 @@ export default definePlugin({
|
|||
settings,
|
||||
|
||||
patches: [{
|
||||
find: ".BEGINNING_DM.format",
|
||||
find: "#{intl::BEGINNING_DM}",
|
||||
replacement: {
|
||||
match: /BEGINNING_DM\.format\(\{.+?\}\),(?=.{0,100}userId:(\i\.getRecipientId\(\)))/,
|
||||
replace: "$& $self.ContributorDmWarningCard({ userId: $1 }),"
|
||||
match: /#{intl::BEGINNING_DM},{.+?}\),(?=.{0,300}(\i)\.isMultiUserDM)/,
|
||||
replace: "$& $self.renderContributorDmWarningCard({ channel: $1 }),"
|
||||
}
|
||||
}],
|
||||
|
||||
|
@ -235,7 +235,8 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
|
||||
ContributorDmWarningCard: ErrorBoundary.wrap(({ userId }) => {
|
||||
renderContributorDmWarningCard: ErrorBoundary.wrap(({ channel }) => {
|
||||
const userId = channel.getRecipientId();
|
||||
if (!isPluginDev(userId)) return null;
|
||||
if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id)) return null;
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.ACCOUNT_SPEAKING_WHILE_MUTED",
|
||||
find: "#{intl::ACCOUNT_SPEAKING_WHILE_MUTED}",
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@ export default definePlugin({
|
|||
},
|
||||
{
|
||||
// Status emojis
|
||||
find: ".Messages.GUILD_OWNER,",
|
||||
find: "#{intl::GUILD_OWNER}",
|
||||
replacement: {
|
||||
match: /(?<=\.activityEmoji,.+?animate:)\i/,
|
||||
replace: "!0"
|
||||
|
|
|
@ -28,10 +28,18 @@ export default definePlugin({
|
|||
patches: [
|
||||
{
|
||||
find: 'action:"EXPAND_ROLES"',
|
||||
replacement: {
|
||||
match: /(roles:\i(?=.+?(\i)\(!0\)[,;]\i\({action:"EXPAND_ROLES"}\)).+?\[\i,\2\]=\i\.useState\()!1\)/,
|
||||
replace: (_, rest, setExpandedRoles) => `${rest}!0)`
|
||||
}
|
||||
replacement: [
|
||||
{
|
||||
match: /(roles:\i(?=.+?(\i)\(!0\)[,;]\i\({action:"EXPAND_ROLES"}\)).+?\[\i,\2\]=\i\.useState\()!1\)/,
|
||||
replace: (_, rest, setExpandedRoles) => `${rest}!0)`
|
||||
},
|
||||
{
|
||||
// Fix not calculating non-expanded roles because the above patch makes the default "expanded",
|
||||
// which makes the collapse button never show up and calculation never occur
|
||||
match: /(?<=useLayoutEffect\(\(\)=>{if\()\i/,
|
||||
replace: isExpanded => "false"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -86,9 +86,9 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: ".Messages.ATTACHMENT_UTILITIES_SPOILER",
|
||||
find: "#{intl::ATTACHMENT_UTILITIES_SPOILER}",
|
||||
replacement: {
|
||||
match: /(?<=children:\[)(?=.{10,80}tooltip:.{0,100}\i\.\i\.Messages\.ATTACHMENT_UTILITIES_SPOILER)/,
|
||||
match: /(?<=children:\[)(?=.{10,80}tooltip:.{0,100}#{intl::ATTACHMENT_UTILITIES_SPOILER})/,
|
||||
replace: "arguments[0].canEdit!==false?$self.renderIcon(arguments[0]):null,"
|
||||
},
|
||||
},
|
||||
|
|
|
@ -73,8 +73,8 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
async start() {
|
||||
// ArmCord comes with its own arRPC implementation, so this plugin just confuses users
|
||||
if ("armcord" in window) return;
|
||||
// Legcord comes with its own arRPC implementation, so this plugin just confuses users
|
||||
if ("legcord" in window) return;
|
||||
|
||||
if (ws) ws.close();
|
||||
ws = new WebSocket("ws://127.0.0.1:1337"); // try to open WebSocket
|
||||
|
|
|
@ -36,7 +36,7 @@ export default definePlugin({
|
|||
settings,
|
||||
patches: [
|
||||
{
|
||||
find: "BAN_CONFIRM_TITLE.",
|
||||
find: "#{intl::BAN_CONFIRM_TITLE}",
|
||||
replacement: {
|
||||
match: /src:\i\("?\d+"?\)/g,
|
||||
replace: "src:$self.source"
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
|
||||
import { FluxDispatcher, i18n, useMemo } from "@webpack/common";
|
||||
import { FluxDispatcher, useMemo } from "@webpack/common";
|
||||
|
||||
import FolderSideBar from "./FolderSideBar";
|
||||
|
||||
|
@ -172,7 +173,7 @@ export default definePlugin({
|
|||
// Disable expanding and collapsing folders transition in the normal GuildsBar sidebar
|
||||
{
|
||||
predicate: () => !settings.store.keepIcons,
|
||||
match: /(?<=\.Messages\.SERVER_FOLDER_PLACEHOLDER.+?useTransition\)\()/,
|
||||
match: /(?<=#{intl::SERVER_FOLDER_PLACEHOLDER}.+?useTransition\)\()/,
|
||||
replace: "$self.shouldShowTransition(arguments[0])&&"
|
||||
},
|
||||
// If we are rendering the normal GuildsBar sidebar, we avoid rendering guilds from folders that are expanded
|
||||
|
@ -205,7 +206,7 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: ".Messages.DISCODO_DISABLED",
|
||||
find: "#{intl::DISCODO_DISABLED}",
|
||||
predicate: () => settings.store.closeAllHomeButton,
|
||||
replacement: {
|
||||
// Close all folders when clicking the home button
|
||||
|
@ -274,12 +275,16 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
makeGuildsBarGuildListFilter(isBetterFolders: boolean) {
|
||||
return child => {
|
||||
if (isBetterFolders) {
|
||||
return child?.props?.["aria-label"] === i18n.Messages.SERVERS;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return child => {
|
||||
if (isBetterFolders) {
|
||||
try {
|
||||
return child?.props?.["aria-label"] === getIntlMessage("SERVERS");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
},
|
||||
|
||||
makeGuildsBarTreeFilter(isBetterFolders: boolean) {
|
||||
|
|
|
@ -34,9 +34,9 @@ export default definePlugin({
|
|||
},
|
||||
},
|
||||
{
|
||||
find: ".Messages.GIF,",
|
||||
find: "#{intl::GIF}",
|
||||
replacement: {
|
||||
match: /alt:(\i)=(\i\.\i\.Messages\.GIF)(?=,[^}]*\}=(\i))/,
|
||||
match: /alt:(\i)=(\i\.\i\.string\(\i\.\i#{intl::GIF}\))(?=,[^}]*\}=(\i))/,
|
||||
replace:
|
||||
// rename prop so we can always use default value
|
||||
"alt_$$:$1=$self.altify($3)||$2",
|
||||
|
|
|
@ -63,9 +63,9 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: "Messages.NOTE_PLACEHOLDER",
|
||||
find: "#{intl::NOTE_PLACEHOLDER}",
|
||||
replacement: {
|
||||
match: /\.NOTE_PLACEHOLDER,/,
|
||||
match: /#{intl::NOTE_PLACEHOLDER}\),/,
|
||||
replace: "$&spellCheck:!$self.noSpellCheck,"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,11 @@ export default definePlugin({
|
|||
id="vc-view-role-icon"
|
||||
label="View Role Icon"
|
||||
action={() => {
|
||||
openImageModal(`${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/role-icons/${role.id}/${role.icon}.${settings.store.roleIconFileFormat}`);
|
||||
openImageModal({
|
||||
url: `${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/role-icons/${role.id}/${role.icon}.${settings.store.roleIconFileFormat}`,
|
||||
height: 128,
|
||||
width: 128
|
||||
});
|
||||
}}
|
||||
icon={ImageIcon}
|
||||
/>
|
||||
|
|
|
@ -47,7 +47,7 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
{
|
||||
find: ".ADD_ROLE_A11Y_LABEL",
|
||||
find: "#{intl::ADD_ROLE_A11Y_LABEL}",
|
||||
all: true,
|
||||
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout && !Settings.plugins.BetterRoleDot.bothStyles,
|
||||
noWarn: true,
|
||||
|
|
|
@ -60,7 +60,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.AUTH_SESSIONS_SESSION_LOG_OUT",
|
||||
find: "#{intl::AUTH_SESSIONS_SESSION_LOG_OUT}",
|
||||
replacement: [
|
||||
// Replace children with a single label with state
|
||||
{
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
*/
|
||||
|
||||
import { openPluginModal } from "@components/PluginSettings/PluginModal";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { isObjectEmpty } from "@utils/misc";
|
||||
import { Alerts, i18n, Menu, useMemo, useState } from "@webpack/common";
|
||||
import { Alerts, Menu, useMemo, useState } from "@webpack/common";
|
||||
|
||||
import Plugins from "~plugins";
|
||||
|
||||
|
@ -48,7 +49,7 @@ export default function PluginsSubmenu() {
|
|||
query={query}
|
||||
onChange={setQuery}
|
||||
ref={ref}
|
||||
placeholder={i18n.Messages.SEARCH}
|
||||
placeholder={getIntlMessage("SEARCH")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
import { definePluginSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { waitFor } from "@webpack";
|
||||
import { ComponentDispatch, FocusLock, i18n, Menu, useEffect, useRef } from "@webpack/common";
|
||||
import { ComponentDispatch, FocusLock, Menu, useEffect, useRef } from "@webpack/common";
|
||||
import type { HTMLAttributes, ReactElement } from "react";
|
||||
|
||||
import PluginsSubmenu from "./PluginsSubmenu";
|
||||
|
@ -111,7 +112,7 @@ export default definePlugin({
|
|||
predicate: () => settings.store.disableFade
|
||||
},
|
||||
{ // Load menu TOC eagerly
|
||||
find: "Messages.USER_SETTINGS_WITH_BUILD_OVERRIDE.format",
|
||||
find: "#{intl::USER_SETTINGS_WITH_BUILD_OVERRIDE}",
|
||||
replacement: {
|
||||
match: /(\i)\(this,"handleOpenSettingsContextMenu",.{0,100}?null!=\i&&.{0,100}?(await Promise\.all[^};]*?\)\)).*?,(?=\1\(this)/,
|
||||
replace: "$&(async ()=>$2)(),"
|
||||
|
@ -119,7 +120,7 @@ export default definePlugin({
|
|||
predicate: () => settings.store.eagerLoad
|
||||
},
|
||||
{ // Settings cog context menu
|
||||
find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL",
|
||||
find: "#{intl::USER_SETTINGS_ACTIONS_MENU_LABEL}",
|
||||
replacement: [
|
||||
{
|
||||
match: /(EXPERIMENTS:.+?)(\(0,\i.\i\)\(\))(?=\.filter\(\i=>\{let\{section:\i\}=)/,
|
||||
|
@ -159,7 +160,7 @@ export default definePlugin({
|
|||
if (item.section === "HEADER") {
|
||||
items.push({ label: item.label, items: [] });
|
||||
} else if (item.section === "DIVIDER") {
|
||||
items.push({ label: i18n.Messages.OTHER_OPTIONS, items: [] });
|
||||
items.push({ label: getIntlMessage("OTHER_OPTIONS"), items: [] });
|
||||
} else {
|
||||
items.at(-1)!.items.push(item);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,11 @@ export const handleViewPreview = async ({ guildId, channelId, ownerId }: Applica
|
|||
const previewUrl = await ApplicationStreamPreviewStore.getPreviewURL(guildId, channelId, ownerId);
|
||||
if (!previewUrl) return;
|
||||
|
||||
openImageModal(previewUrl);
|
||||
openImageModal({
|
||||
url: previewUrl,
|
||||
height: 720,
|
||||
width: 1280
|
||||
});
|
||||
};
|
||||
|
||||
export const addViewStreamContext: NavContextMenuPatchCallback = (children, { userId }: { userId: string | bigint; }) => {
|
||||
|
|
|
@ -45,8 +45,8 @@ export default definePlugin({
|
|||
{
|
||||
find: ".embedWrapper,embed",
|
||||
replacement: [{
|
||||
match: /\.embedWrapper(?=.+?channel_id:(\i)\.id)/g,
|
||||
replace: "$&+($1.nsfw?' vc-nsfw-img':'')"
|
||||
match: /\.container/,
|
||||
replace: "$&+(this.props.channel.nsfw? ' vc-nsfw-img': '')"
|
||||
}]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -14,7 +14,7 @@ import definePlugin, { OptionType, StartAt } from "@utils/types";
|
|||
import { findByCodeLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
||||
import { Button, Forms, ThemeStore, useStateFromStores } from "@webpack/common";
|
||||
|
||||
const ColorPicker = findComponentByCodeLazy(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
||||
const ColorPicker = findComponentByCodeLazy("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", ".BACKGROUND_PRIMARY)");
|
||||
|
||||
const colorPresets = [
|
||||
"#1E1514", "#172019", "#13171B", "#1C1C28", "#402D2D",
|
||||
|
|
|
@ -66,6 +66,13 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: 'react-spring: The "interpolate" function',
|
||||
replacement: {
|
||||
match: /,console.warn\('react-spring: The "interpolate" function is deprecated in v10 \(use "to" instead\)'\)/,
|
||||
replace: ""
|
||||
}
|
||||
},
|
||||
{
|
||||
find: 'console.warn("Window state not initialized"',
|
||||
replacement: {
|
||||
|
@ -119,7 +126,28 @@ export default definePlugin({
|
|||
{
|
||||
find: "Slow dispatch on",
|
||||
replacement: {
|
||||
match: /\i\.totalTime>\i&&\i\.verbose\("Slow dispatch on ".+?\)\);/,
|
||||
match: /\i\.totalTime>100&&\i\.verbose\("Slow dispatch on ".+?\)\);/,
|
||||
replace: ""
|
||||
}
|
||||
},
|
||||
// Zustand section
|
||||
{
|
||||
find: "[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.",
|
||||
replacement: [
|
||||
{
|
||||
match: /&&console\.warn\("\[DEPRECATED\] Passing a vanilla store will be unsupported in a future version\. Instead use `import { useStore } from 'zustand'`\."\)/,
|
||||
replace: ""
|
||||
},
|
||||
{
|
||||
match: /console\.warn\("\[DEPRECATED\] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`\. They can be imported from 'zustand\/traditional'\. https:\/\/github\.com\/pmndrs\/zustand\/discussions\/1937"\),/,
|
||||
replace: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
find: "[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.",
|
||||
replacement: {
|
||||
match: /console\.warn\("\[DEPRECATED\] `getStorage`, `serialize` and `deserialize` options are deprecated\. Use `storage` option instead\."\),/,
|
||||
replace: ""
|
||||
}
|
||||
},
|
||||
|
@ -140,5 +168,5 @@ export default definePlugin({
|
|||
replace: "$self.NoopLogger()"
|
||||
}
|
||||
}
|
||||
],
|
||||
]
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel, getCurrentGuild } from "@utils/discord";
|
||||
import { runtimeHashMessageKey } from "@utils/intlHash";
|
||||
import { SYM_LAZY_CACHED, SYM_LAZY_GET } from "@utils/lazy";
|
||||
import { relaunch } from "@utils/native";
|
||||
import { canonicalizeMatch, canonicalizeReplace, canonicalizeReplacement } from "@utils/patches";
|
||||
|
@ -104,6 +105,7 @@ function makeShortcuts() {
|
|||
canonicalizeMatch,
|
||||
canonicalizeReplace,
|
||||
canonicalizeReplacement,
|
||||
runtimeHashMessageKey,
|
||||
fakeRender: (component: ComponentType, props: any) => {
|
||||
const prevWin = fakeRenderWin?.deref();
|
||||
const win = prevWin?.closed === false
|
||||
|
|
|
@ -25,7 +25,7 @@ export default definePlugin({
|
|||
authors: [Devs.Obsidian, Devs.Nuckyz],
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.PREVIEW_BYTES_LEFT.format(",
|
||||
find: "#{intl::PREVIEW_BYTES_LEFT}",
|
||||
replacement: {
|
||||
match: /\.footerGap.+?url:\i,fileName:\i,fileSize:\i}\),(?<=fileContents:(\i),bytesLeft:(\i).+?)/g,
|
||||
replace: "$&$self.addCopyButton({fileContents:$1,bytesLeft:$2}),"
|
||||
|
|
|
@ -67,7 +67,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.ERRORS_UNEXPECTED_CRASH",
|
||||
find: "#{intl::ERRORS_UNEXPECTED_CRASH}",
|
||||
replacement: {
|
||||
match: /this\.setState\((.+?)\)/,
|
||||
replace: "$self.handleCrash(this,$1);"
|
||||
|
|
|
@ -41,7 +41,7 @@ export default definePlugin({
|
|||
{
|
||||
find: "DefaultCustomizationSections",
|
||||
replacement: {
|
||||
match: /(?<=USER_SETTINGS_AVATAR_DECORATION},"decoration"\),)/,
|
||||
match: /(?<=#{intl::USER_SETTINGS_AVATAR_DECORATION}\)},"decoration"\),)/,
|
||||
replace: "$self.DecorSection(),"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -93,7 +93,7 @@ export const useAuthorizationStore = proxyLazy(() => zustandCreate(
|
|||
} as AuthorizationState),
|
||||
{
|
||||
name: "decor-auth",
|
||||
getStorage: () => indexedDBStorage,
|
||||
storage: indexedDBStorage,
|
||||
partialize: state => ({ tokens: state.tokens }),
|
||||
onRehydrateStorage: () => state => state?.init()
|
||||
}
|
||||
|
|
|
@ -95,24 +95,39 @@ export const useUsersDecorationsStore = proxyLazy(() => zustandCreate((set: any,
|
|||
} as UsersDecorationsState)));
|
||||
|
||||
export function useUserDecorAvatarDecoration(user?: User): AvatarDecoration | null | undefined {
|
||||
const [decorAvatarDecoration, setDecorAvatarDecoration] = useState<string | null>(user ? useUsersDecorationsStore.getState().getAsset(user.id) ?? null : null);
|
||||
try {
|
||||
const [decorAvatarDecoration, setDecorAvatarDecoration] = useState<string | null>(user ? useUsersDecorationsStore.getState().getAsset(user.id) ?? null : null);
|
||||
|
||||
useEffect(() => {
|
||||
const destructor = useUsersDecorationsStore.subscribe(
|
||||
state => {
|
||||
if (!user) return;
|
||||
const newDecorAvatarDecoration = state.getAsset(user.id);
|
||||
if (!newDecorAvatarDecoration) return;
|
||||
if (decorAvatarDecoration !== newDecorAvatarDecoration) setDecorAvatarDecoration(newDecorAvatarDecoration);
|
||||
}
|
||||
);
|
||||
useEffect(() => {
|
||||
const destructor = (() => {
|
||||
try {
|
||||
return useUsersDecorationsStore.subscribe(
|
||||
state => {
|
||||
if (!user) return;
|
||||
const newDecorAvatarDecoration = state.getAsset(user.id);
|
||||
if (!newDecorAvatarDecoration) return;
|
||||
if (decorAvatarDecoration !== newDecorAvatarDecoration) setDecorAvatarDecoration(newDecorAvatarDecoration);
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
return () => { };
|
||||
}
|
||||
})();
|
||||
|
||||
if (user) {
|
||||
const { fetch: fetchUserDecorAvatarDecoration } = useUsersDecorationsStore.getState();
|
||||
fetchUserDecorAvatarDecoration(user.id);
|
||||
}
|
||||
return destructor;
|
||||
}, []);
|
||||
try {
|
||||
if (user) {
|
||||
const { fetch: fetchUserDecorAvatarDecoration } = useUsersDecorationsStore.getState();
|
||||
fetchUserDecorAvatarDecoration(user.id);
|
||||
}
|
||||
} catch { }
|
||||
|
||||
return decorAvatarDecoration ? { asset: decorAvatarDecoration, skuId: SKU_ID } : null;
|
||||
return destructor;
|
||||
}, []);
|
||||
|
||||
return decorAvatarDecoration ? { asset: decorAvatarDecoration, skuId: SKU_ID } : null;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
*/
|
||||
|
||||
import { PlusIcon } from "@components/Icons";
|
||||
import { i18n, Text } from "@webpack/common";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { Text } from "@webpack/common";
|
||||
import { HTMLProps } from "react";
|
||||
|
||||
import { DecorationGridItem } from ".";
|
||||
|
@ -24,7 +25,7 @@ export default function DecorationGridCreate(props: DecorationGridCreateProps) {
|
|||
variant="text-xs/normal"
|
||||
color="header-primary"
|
||||
>
|
||||
{i18n.Messages.CREATE}
|
||||
{getIntlMessage("CREATE")}
|
||||
</Text>
|
||||
</DecorationGridItem >;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
*/
|
||||
|
||||
import { NoEntrySignIcon } from "@components/Icons";
|
||||
import { i18n, Text } from "@webpack/common";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { Text } from "@webpack/common";
|
||||
import { HTMLProps } from "react";
|
||||
|
||||
import { DecorationGridItem } from ".";
|
||||
|
@ -24,7 +25,7 @@ export default function DecorationGridNone(props: DecorationGridNoneProps) {
|
|||
variant="text-xs/normal"
|
||||
color="header-primary"
|
||||
>
|
||||
{i18n.Messages.NONE}
|
||||
{getIntlMessage("NONE")}
|
||||
</Text>
|
||||
</DecorationGridItem >;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import { openInviteModal } from "@utils/discord";
|
|||
import { Margins } from "@utils/margins";
|
||||
import { classes, copyWithToast } from "@utils/misc";
|
||||
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { Queue } from "@utils/Queue";
|
||||
import { findComponentByCodeLazy } from "@webpack";
|
||||
import { Alerts, Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Parser, Text, Tooltip, useEffect, UserStore, UserUtils, useState } from "@webpack/common";
|
||||
import { User } from "discord-types/general";
|
||||
|
@ -49,6 +50,8 @@ interface SectionHeaderProps {
|
|||
section: Section;
|
||||
}
|
||||
|
||||
const fetchAuthorsQueue = new Queue();
|
||||
|
||||
function SectionHeader({ section }: SectionHeaderProps) {
|
||||
const hasSubtitle = typeof section.subtitle !== "undefined";
|
||||
const hasAuthorIds = typeof section.authorIds !== "undefined";
|
||||
|
@ -56,17 +59,18 @@ function SectionHeader({ section }: SectionHeaderProps) {
|
|||
const [authors, setAuthors] = useState<User[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
fetchAuthorsQueue.push(async () => {
|
||||
if (!section.authorIds) return;
|
||||
|
||||
for (const authorId of section.authorIds) {
|
||||
const author = UserStore.getUser(authorId) ?? await UserUtils.getUser(authorId);
|
||||
const author = UserStore.getUser(authorId) ?? await UserUtils.getUser(authorId).catch(() => null);
|
||||
if (author == null) continue;
|
||||
|
||||
setAuthors(authors => [...authors, author]);
|
||||
}
|
||||
})();
|
||||
});
|
||||
}, [section.authorIds]);
|
||||
|
||||
|
||||
return <div>
|
||||
<Flex>
|
||||
<Forms.FormTitle style={{ flexGrow: 1 }}>{section.title}</Forms.FormTitle>
|
||||
|
|
|
@ -20,7 +20,7 @@ import { AvatarDecorationModalPreview } from "../components";
|
|||
const FileUpload = findComponentByCodeLazy("fileUploadInput,");
|
||||
|
||||
const { HelpMessage, HelpMessageTypes } = mapMangledModuleLazy('POSITIVE=3]="POSITIVE', {
|
||||
HelpMessageTypes: filters.byProps("POSITIVE", "WARNING"),
|
||||
HelpMessageTypes: filters.byProps("POSITIVE", "WARNING", "INFO"),
|
||||
HelpMessage: filters.byCode(".iconDiv")
|
||||
});
|
||||
|
||||
|
@ -119,8 +119,8 @@ function CreateDecorationModal(props: ModalProps) {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Forms.FormText type="description" className={Margins.bottom16}>
|
||||
<br />You can receive updates on your decoration's review by joining <Link
|
||||
<HelpMessage messageType={HelpMessageTypes.INFO} className={Margins.bottom8}>
|
||||
To receive updates on your decoration's review, join <Link
|
||||
href={`https://discord.gg/${INVITE_KEY}`}
|
||||
onClick={async e => {
|
||||
e.preventDefault();
|
||||
|
@ -138,8 +138,8 @@ function CreateDecorationModal(props: ModalProps) {
|
|||
}}
|
||||
>
|
||||
Decor's Discord server
|
||||
</Link>.
|
||||
</Forms.FormText>
|
||||
</Link> and allow direct messages.
|
||||
</HelpMessage>
|
||||
</ErrorBoundary>
|
||||
</ModalContent>
|
||||
<ModalFooter className={cl("modal-footer")}>
|
||||
|
|
|
@ -27,7 +27,7 @@ export default definePlugin({
|
|||
authors: [Devs.Nuckyz],
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.BOT_CALL_IDLE_DISCONNECT",
|
||||
find: "#{intl::BOT_CALL_IDLE_DISCONNECT_2}",
|
||||
replacement: {
|
||||
match: /,?(?=\i\(this,"idleTimeout",new \i\.\i\))/,
|
||||
replace: ";return;"
|
||||
|
|
|
@ -20,11 +20,11 @@ import { addPreEditListener, addPreSendListener, removePreEditListener, removePr
|
|||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
||||
import { getCurrentGuild } from "@utils/discord";
|
||||
import { getCurrentGuild, getEmojiURL } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import definePlugin, { OptionType, Patch } from "@utils/types";
|
||||
import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
|
||||
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, IconUtils, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
||||
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
||||
import type { Emoji } from "@webpack/types";
|
||||
import type { Message } from "discord-types/general";
|
||||
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
||||
|
@ -194,6 +194,26 @@ const hasExternalStickerPerms = (channelId: string) => hasPermission(channelId,
|
|||
const hasEmbedPerms = (channelId: string) => hasPermission(channelId, PermissionsBits.EMBED_LINKS);
|
||||
const hasAttachmentPerms = (channelId: string) => hasPermission(channelId, PermissionsBits.ATTACH_FILES);
|
||||
|
||||
function makeBypassPatches(): Omit<Patch, "plugin"> {
|
||||
const mapping: Array<{ func: string, predicate?: () => boolean; }> = [
|
||||
{ func: "canUseCustomStickersEverywhere", predicate: () => settings.store.enableStickerBypass },
|
||||
{ func: "canUseHighVideoUploadQuality", predicate: () => settings.store.enableStreamQualityBypass },
|
||||
{ func: "canStreamQuality", predicate: () => settings.store.enableStreamQualityBypass },
|
||||
{ func: "canUseClientThemes" },
|
||||
{ func: "canUseCustomNotificationSounds" },
|
||||
{ func: "canUsePremiumAppIcons" }
|
||||
];
|
||||
|
||||
return {
|
||||
find: "canUseCustomStickersEverywhere:",
|
||||
replacement: mapping.map(({ func, predicate }) => ({
|
||||
match: new RegExp(String.raw`(?<=${func}:function\(\i(?:,\i)?\){)`),
|
||||
replace: "return true;",
|
||||
predicate
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "FakeNitro",
|
||||
authors: [Devs.Arjix, Devs.D3SOX, Devs.Ven, Devs.fawn, Devs.captain, Devs.Nuckyz, Devs.AutumnVN],
|
||||
|
@ -203,6 +223,8 @@ export default definePlugin({
|
|||
settings,
|
||||
|
||||
patches: [
|
||||
// General bypass patches
|
||||
makeBypassPatches(),
|
||||
// Patch the emoji picker in voice calls to not be bypassed by fake nitro
|
||||
{
|
||||
find: "emojiItemDisabled]",
|
||||
|
@ -252,15 +274,6 @@ export default definePlugin({
|
|||
replace: (_, rest1, rest2) => `${rest1},fakeNitroOriginal){if(!fakeNitroOriginal)return false;${rest2}`
|
||||
}
|
||||
},
|
||||
// Allow stickers to be sent everywhere
|
||||
{
|
||||
find: "canUseCustomStickersEverywhere:",
|
||||
predicate: () => settings.store.enableStickerBypass,
|
||||
replacement: {
|
||||
match: /(?<=canUseCustomStickersEverywhere:)\i/,
|
||||
replace: "()=>true"
|
||||
},
|
||||
},
|
||||
// Make stickers always available
|
||||
{
|
||||
find: '"SENDABLE"',
|
||||
|
@ -270,44 +283,22 @@ export default definePlugin({
|
|||
replace: "true?"
|
||||
}
|
||||
},
|
||||
// Allow streaming with high quality
|
||||
{
|
||||
find: "canUseHighVideoUploadQuality:",
|
||||
predicate: () => settings.store.enableStreamQualityBypass,
|
||||
replacement: [
|
||||
"canUseHighVideoUploadQuality",
|
||||
"canStreamQuality",
|
||||
].map(func => {
|
||||
return {
|
||||
match: new RegExp(`(?<=${func}:)\\i`, "g"),
|
||||
replace: "()=>true"
|
||||
};
|
||||
})
|
||||
},
|
||||
// Remove boost requirements to stream with high quality
|
||||
{
|
||||
find: "STREAM_FPS_OPTION.format",
|
||||
find: "#{intl::STREAM_FPS_OPTION}",
|
||||
predicate: () => settings.store.enableStreamQualityBypass,
|
||||
replacement: {
|
||||
match: /guildPremiumTier:\i\.\i\.TIER_\d,?/g,
|
||||
replace: ""
|
||||
}
|
||||
},
|
||||
// Allow client themes to be changeable
|
||||
{
|
||||
find: "canUseClientThemes:",
|
||||
replacement: {
|
||||
match: /(?<=canUseClientThemes:)\i/,
|
||||
replace: "()=>true"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: '"UserSettingsProtoStore"',
|
||||
replacement: [
|
||||
{
|
||||
// Overwrite incoming connection settings proto with our local settings
|
||||
match: /function (\i)\((\i)\){(?=.*CONNECTION_OPEN:\1)/,
|
||||
replace: (m, funcName, props) => `${m}$self.handleProtoChange(${props}.userSettingsProto,${props}.user);`
|
||||
match: /CONNECTION_OPEN:function\((\i)\){/,
|
||||
replace: (m, props) => `${m}$self.handleProtoChange(${props}.userSettingsProto,${props}.user);`
|
||||
},
|
||||
{
|
||||
// Overwrite non local proto changes with our local settings
|
||||
|
@ -359,13 +350,13 @@ export default definePlugin({
|
|||
{
|
||||
// Filter attachments to remove fake nitro stickers or emojis
|
||||
predicate: () => settings.store.transformStickers,
|
||||
match: /renderAttachments\(\i\){let{attachments:(\i).+?;/,
|
||||
match: /renderAttachments\(\i\){.+?{attachments:(\i).+?;/,
|
||||
replace: (m, attachments) => `${m}${attachments}=$self.filterAttachments(${attachments});`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
find: ".Messages.STICKER_POPOUT_UNJOINED_PRIVATE_GUILD_DESCRIPTION.format",
|
||||
find: "#{intl::STICKER_POPOUT_UNJOINED_PRIVATE_GUILD_DESCRIPTION}",
|
||||
predicate: () => settings.store.transformStickers,
|
||||
replacement: [
|
||||
{
|
||||
|
@ -390,7 +381,7 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: ".Messages.EMOJI_POPOUT_UNJOINED_DISCOVERABLE_GUILD_DESCRIPTION",
|
||||
find: "#{intl::EMOJI_POPOUT_UNJOINED_DISCOVERABLE_GUILD_DESCRIPTION}",
|
||||
predicate: () => settings.store.transformEmojis,
|
||||
replacement: {
|
||||
// Add the fake nitro emoji notice
|
||||
|
@ -398,14 +389,6 @@ export default definePlugin({
|
|||
replace: (_, reactNode, props) => `$self.addFakeNotice(${FakeNoticeType.Emoji},${reactNode},!!${props}?.fakeNitroNode?.fake)`
|
||||
}
|
||||
},
|
||||
// Allow using custom app icons
|
||||
{
|
||||
find: "canUsePremiumAppIcons:",
|
||||
replacement: {
|
||||
match: /(?<=canUsePremiumAppIcons:)\i/,
|
||||
replace: "()=>true"
|
||||
}
|
||||
},
|
||||
// Separate patch for allowing using custom app icons
|
||||
{
|
||||
find: /\.getCurrentDesktopIcon.{0,25}\.isPremium/,
|
||||
|
@ -421,14 +404,6 @@ export default definePlugin({
|
|||
match: /(?<=type:"(?:SOUNDBOARD_SOUNDS_RECEIVED|GUILD_SOUNDBOARD_SOUND_CREATE|GUILD_SOUNDBOARD_SOUND_UPDATE|GUILD_SOUNDBOARD_SOUNDS_UPDATE)".+?available:)\i\.available/g,
|
||||
replace: "true"
|
||||
}
|
||||
},
|
||||
// Allow using custom notification sounds
|
||||
{
|
||||
find: "canUseCustomNotificationSounds:",
|
||||
replacement: {
|
||||
match: /(?<=canUseCustomNotificationSounds:)\i/,
|
||||
replace: "()=>true"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
|
@ -945,7 +920,7 @@ export default definePlugin({
|
|||
|
||||
const emojiString = `<${emoji.animated ? "a" : ""}:${emoji.originalName || emoji.name}:${emoji.id}>`;
|
||||
|
||||
const url = new URL(IconUtils.getEmojiURL({ id: emoji.id, animated: emoji.animated, size: s.emojiSize }));
|
||||
const url = new URL(getEmojiURL(emoji.id, emoji.animated, s.emojiSize));
|
||||
url.searchParams.set("size", s.emojiSize.toString());
|
||||
url.searchParams.set("name", emoji.name);
|
||||
|
||||
|
@ -978,7 +953,7 @@ export default definePlugin({
|
|||
|
||||
hasBypass = true;
|
||||
|
||||
const url = new URL(IconUtils.getEmojiURL({ id: emoji.id, animated: emoji.animated, size: s.emojiSize }));
|
||||
const url = new URL(getEmojiURL(emoji.id, emoji.animated, s.emojiSize));
|
||||
url.searchParams.set("size", s.emojiSize.toString());
|
||||
url.searchParams.set("name", emoji.name);
|
||||
|
||||
|
|
|
@ -108,10 +108,10 @@ interface ProfileModalProps {
|
|||
isTryItOutFlow: boolean;
|
||||
}
|
||||
|
||||
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
||||
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", ".BACKGROUND_PRIMARY)");
|
||||
const ProfileModal = findComponentByCodeLazy<ProfileModalProps>("isTryItOutFlow:", "pendingThemeColors:", "pendingAvatarDecoration:", "EDIT_PROFILE_BANNER");
|
||||
|
||||
const requireColorPicker = extractAndLoadChunksLazy(["USER_SETTINGS_PROFILE_COLOR_DEFAULT_BUTTON.format"], /createPromise:\(\)=>\i\.\i(\("?.+?"?\)).then\(\i\.bind\(\i,"?(.+?)"?\)\)/);
|
||||
const requireColorPicker = extractAndLoadChunksLazy(["#{intl::USER_SETTINGS_PROFILE_COLOR_DEFAULT_BUTTON}"], /createPromise:\(\)=>\i\.\i(\("?.+?"?\)).then\(\i\.bind\(\i,"?(.+?)"?\)\)/);
|
||||
|
||||
export default definePlugin({
|
||||
name: "FakeProfileThemes",
|
||||
|
@ -126,9 +126,9 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: ".USER_SETTINGS_RESET_PROFILE_THEME",
|
||||
find: "#{intl::USER_SETTINGS_RESET_PROFILE_THEME}",
|
||||
replacement: {
|
||||
match: /RESET_PROFILE_THEME}\)(?<=color:(\i),.{0,500}?color:(\i),.{0,500}?)/,
|
||||
match: /#{intl::USER_SETTINGS_RESET_PROFILE_THEME}\)}\)(?<=color:(\i),.{0,500}?color:(\i),.{0,500}?)/,
|
||||
replace: "$&,$self.addCopy3y3Button({primary:$1,accent:$2})"
|
||||
}
|
||||
}
|
||||
|
|
3
src/plugins/fixImagesQuality/README.md
Normal file
3
src/plugins/fixImagesQuality/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Fix Images Quality
|
||||
|
||||
Prevents images from being loaded as webp, which can cause quality loss
|
23
src/plugins/fixImagesQuality/index.ts
Normal file
23
src/plugins/fixImagesQuality/index.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
name: "FixImagesQuality",
|
||||
description: "Prevents images from being loaded as webp, which can cause quality loss",
|
||||
authors: [Devs.Nuckyz],
|
||||
patches: [
|
||||
{
|
||||
find: "getFormatQuality(){",
|
||||
replacement: {
|
||||
match: /(?<=null;return )\i\.\i&&\(\i\|\|!\i\.isAnimated.+?:(?=\i&&\(\i="png"\))/,
|
||||
replace: ""
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
|
@ -27,7 +27,7 @@ export default definePlugin({
|
|||
authors: [Devs.D3SOX, Devs.Nickyux],
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.GUILD_OWNER,",
|
||||
find: "#{intl::GUILD_OWNER}",
|
||||
replacement: {
|
||||
match: /,isOwner:(\i),/,
|
||||
replace: ",_isOwner:$1=$self.isGuildOwner(e),"
|
||||
|
|
|
@ -26,7 +26,7 @@ export default definePlugin({
|
|||
{
|
||||
find: ".PANEL}),nicknameIcons",
|
||||
replacement: {
|
||||
match: /USER_PROFILE_MEMBER_SINCE,.{0,100}userId:(\i\.id)}\)}\)/,
|
||||
match: /#{intl::USER_PROFILE_MEMBER_SINCE}\),.{0,100}userId:(\i\.id)}\)}\)/,
|
||||
replace: "$&,$self.FriendsSinceComponent({userId:$1,isSidebar:true})"
|
||||
}
|
||||
},
|
||||
|
@ -34,7 +34,7 @@ export default definePlugin({
|
|||
{
|
||||
find: "action:\"PRESS_APP_CONNECTION\"",
|
||||
replacement: {
|
||||
match: /USER_PROFILE_MEMBER_SINCE,.{0,100}userId:(\i\.id),.{0,100}}\)}\),/,
|
||||
match: /#{intl::USER_PROFILE_MEMBER_SINCE}\),.{0,100}userId:(\i\.id),.{0,100}}\)}\),/,
|
||||
replace: "$&,$self.FriendsSinceComponent({userId:$1,isSidebar:false}),"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { migratePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { NoopComponent } from "@utils/react";
|
||||
import definePlugin from "@utils/types";
|
||||
import { filters, findByPropsLazy, waitFor } from "@webpack";
|
||||
import { ChannelStore, ContextMenuApi, i18n, UserStore } from "@webpack/common";
|
||||
import { ChannelStore, ContextMenuApi, UserStore } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
const { useMessageMenu } = findByPropsLazy("useMessageMenu");
|
||||
|
@ -41,7 +42,7 @@ function MessageMenu({ message, channel, onHeightUpdate }) {
|
|||
|
||||
return useMessageMenu({
|
||||
navId: "message-actions",
|
||||
ariaLabel: i18n.Messages.MESSAGE_UTILITIES_A11Y_LABEL,
|
||||
ariaLabel: getIntlMessage("MESSAGE_UTILITIES_A11Y_LABEL"),
|
||||
|
||||
message,
|
||||
channel,
|
||||
|
@ -72,7 +73,7 @@ const contextMenuPatch: NavContextMenuPatchCallback = (children, props: MessageA
|
|||
|
||||
const group = findGroupChildrenByChildId("devmode-copy-id", children, true);
|
||||
group?.push(
|
||||
CopyIdMenuItem({ id: props.message.author.id, label: i18n.Messages.COPY_ID_AUTHOR })
|
||||
CopyIdMenuItem({ id: props.message.author.id, label: getIntlMessage("COPY_ID_AUTHOR") })
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.ACCOUNT_SPEAKING_WHILE_MUTED",
|
||||
find: "#{intl::ACCOUNT_SPEAKING_WHILE_MUTED}",
|
||||
replacement: {
|
||||
match: /this\.renderNameZone\(\).+?children:\[/,
|
||||
replace: "$&$self.GameActivityToggleButton(),"
|
||||
|
|
|
@ -166,7 +166,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.WELCOME_CTA_LABEL",
|
||||
find: "#{intl::WELCOME_CTA_LABEL}",
|
||||
replacement: {
|
||||
match: /innerClassName:\i\.welcomeCTAButton,(?<={channel:\i,message:\i}=(\i).{0,400}?)/,
|
||||
replace: "$&onContextMenu:(vcEvent)=>$self.pickSticker(vcEvent, $1),"
|
||||
|
|
|
@ -260,9 +260,9 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: ".Messages.SETTINGS_GAMES_TOGGLE_OVERLAY",
|
||||
find: "#{intl::SETTINGS_GAMES_TOGGLE_OVERLAY}",
|
||||
replacement: {
|
||||
match: /\.Messages\.SETTINGS_GAMES_TOGGLE_OVERLAY.+?}\(\),(?<={overlay:\i,.+?=(\i),.+?)(?=!(\i))/,
|
||||
match: /#{intl::SETTINGS_GAMES_TOGGLE_OVERLAY}.+?}\(\),(?<={overlay:\i,.+?=(\i),.+?)(?=!(\i))/,
|
||||
replace: (m, props, nowPlaying) => `${m}$self.renderToggleGameActivityButton(${props},${nowPlaying}),`
|
||||
}
|
||||
},
|
||||
|
|
|
@ -156,14 +156,10 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.OPEN_IN_BROWSER",
|
||||
find: ".contain,SCALE_DOWN:",
|
||||
replacement: {
|
||||
// there are 2 image thingies. one for carosuel and one for the single image.
|
||||
// so thats why i added global flag.
|
||||
// also idk if this patch is good, should it be more specific?
|
||||
// https://regex101.com/r/xfvNvV/1
|
||||
match: /return.{1,200}\.wrapper.{1,200}src:\i,/g,
|
||||
replace: `$&id: '${ELEMENT_ID}',`
|
||||
match: /\.slide,\i\),/g,
|
||||
replace: `$&id:"${ELEMENT_ID}",`
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -183,15 +179,13 @@ export default definePlugin({
|
|||
{
|
||||
match: /componentWillUnmount\(\){/,
|
||||
replace: "$&$self.unMountMagnifier();"
|
||||
},
|
||||
|
||||
{
|
||||
match: /componentDidUpdate\(\i\){/,
|
||||
replace: "$&$self.updateMagnifier(this);"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
find: ".carouselModal",
|
||||
replacement: {
|
||||
match: /(?<=\.carouselModal.{0,100}onClick:)\i,/,
|
||||
replace: "()=>{},"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
|
@ -226,6 +220,11 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
|
||||
updateMagnifier(instance) {
|
||||
this.unMountMagnifier();
|
||||
this.renderMagnifier(instance);
|
||||
},
|
||||
|
||||
unMountMagnifier() {
|
||||
this.root?.unmount();
|
||||
this.currentMagnifierElement = null;
|
||||
|
|
|
@ -23,12 +23,3 @@
|
|||
|
||||
/* https://googlechrome.github.io/samples/image-rendering-pixelated/index.html */
|
||||
}
|
||||
|
||||
/* make the carousel take up less space so we can click the backdrop and exit out of it */
|
||||
[class*="modalCarouselWrapper_"] {
|
||||
top: 0 !important;
|
||||
}
|
||||
|
||||
[class*="carouselModal_"] {
|
||||
height: 0 !important;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ export default definePlugin({
|
|||
patches: [
|
||||
// Counts header
|
||||
{
|
||||
find: ".FRIENDS_ALL_HEADER",
|
||||
find: "#{intl::FRIENDS_ALL_HEADER}",
|
||||
replacement: {
|
||||
match: /toString\(\)\}\);case (\i\.\i)\.BLOCKED/,
|
||||
replace: 'toString()});case $1.IMPLICIT:return "Implicit — "+arguments[1];case $1.BLOCKED'
|
||||
|
@ -48,9 +48,9 @@ export default definePlugin({
|
|||
},
|
||||
// Sections header
|
||||
{
|
||||
find: ".FRIENDS_SECTION_ONLINE",
|
||||
find: "#{intl::FRIENDS_SECTION_ONLINE}",
|
||||
replacement: {
|
||||
match: /(\(0,\i\.jsx\)\(\i\.TabBar\.Item,\{id:\i\.\i)\.BLOCKED,className:([^\s]+?)\.item,children:\i\.\i\.Messages\.BLOCKED\}\)/,
|
||||
match: /(\(0,\i\.jsx\)\(\i\.TabBar\.Item,\{id:\i\.\i)\.BLOCKED,className:([^\s]+?)\.item,children:\i\.\i\.string\(\i\.\i#{intl::BLOCKED}\)\}\)/,
|
||||
replace: "$1.IMPLICIT,className:$2.item,children:\"Implicit\"}),$&"
|
||||
},
|
||||
},
|
||||
|
@ -117,7 +117,7 @@ export default definePlugin({
|
|||
|
||||
wrapSort(comparator: Function, row: any) {
|
||||
return row.type === 5
|
||||
? -UserAffinitiesStore.getUserAffinity(row.user.id)?.affinity ?? 0
|
||||
? -(UserAffinitiesStore.getUserAffinity(row.user.id)?.affinity ?? 0)
|
||||
: comparator(row);
|
||||
},
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ export default definePlugin({
|
|||
patches: [
|
||||
{
|
||||
// Indicator
|
||||
find: ".Messages.MESSAGE_EDITED,",
|
||||
find: "#{intl::MESSAGE_EDITED}",
|
||||
replacement: {
|
||||
match: /let\{className:\i,message:\i[^}]*\}=(\i)/,
|
||||
replace: "try {$1 && $self.INV_REGEX.test($1.message.content) ? $1.content.push($self.indicator()) : null } catch {};$&"
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import * as DataStore from "@api/DataStore";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { ChannelRouter, SelectedChannelStore, SelectedGuildStore } from "@webpack/common";
|
||||
import { ChannelRouter, ChannelStore, NavigationRouter, SelectedChannelStore, SelectedGuildStore } from "@webpack/common";
|
||||
|
||||
export interface LogoutEvent {
|
||||
type: "LOGOUT";
|
||||
|
@ -45,6 +45,16 @@ export default definePlugin({
|
|||
description: "Attempt to navigate to the channel you were in before switching accounts or loading Discord.",
|
||||
authors: [Devs.Nuckyz],
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: '"Switching accounts"',
|
||||
replacement: {
|
||||
match: /goHomeAfterSwitching:\i/,
|
||||
replace: "goHomeAfterSwitching:!1"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
flux: {
|
||||
LOGOUT(e: LogoutEvent) {
|
||||
({ isSwitchingAccount } = e);
|
||||
|
@ -55,7 +65,11 @@ export default definePlugin({
|
|||
isSwitchingAccount = false;
|
||||
|
||||
if (previousCache?.channelId) {
|
||||
ChannelRouter.transitionToChannel(previousCache.channelId);
|
||||
if (ChannelStore.hasChannel(previousCache.channelId)) {
|
||||
ChannelRouter.transitionToChannel(previousCache.channelId);
|
||||
} else {
|
||||
NavigationRouter.transitionToGuild("@me");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".LOADING_DID_YOU_KNOW",
|
||||
find: "#{intl::LOADING_DID_YOU_KNOW}",
|
||||
replacement: [
|
||||
{
|
||||
match: /"_loadingText".+?(?=(\i)\[.{0,10}\.random)/,
|
||||
|
|
|
@ -74,7 +74,7 @@ export default definePlugin({
|
|||
{
|
||||
find: ".invitesDisabledTooltip",
|
||||
replacement: {
|
||||
match: /\.VIEW_AS_ROLES_MENTIONS_WARNING.{0,100}(?=])/,
|
||||
match: /#{intl::VIEW_AS_ROLES_MENTIONS_WARNING}.{0,100}(?=])/,
|
||||
replace: "$&,$self.renderTooltip(arguments[0].guild)"
|
||||
},
|
||||
predicate: () => settings.store.toolTip
|
||||
|
|
|
@ -74,7 +74,7 @@ export default definePlugin({
|
|||
if (msg.deleted === true) return;
|
||||
|
||||
if (isMe) {
|
||||
if (!settings.store.enableDoubleClickToEdit || EditStore.isEditing(channel.id, msg.id)) return;
|
||||
if (!settings.store.enableDoubleClickToEdit || EditStore.isEditing(channel.id, msg.id) || msg.state !== "SENT") return;
|
||||
|
||||
MessageActions.startEditMessage(channel.id, msg.id, msg.content);
|
||||
event.preventDefault();
|
||||
|
|
|
@ -24,12 +24,12 @@ import { Settings } from "@api/Settings";
|
|||
import { disableStyle, enableStyle } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { classes } from "@utils/misc";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByCodeLazy, findByPropsLazy } from "@webpack";
|
||||
import { ChannelStore, FluxDispatcher, i18n, Menu, MessageStore, Parser, SelectedChannelStore, Timestamp, UserStore, useStateFromStores } from "@webpack/common";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { ChannelStore, FluxDispatcher, Menu, MessageStore, Parser, SelectedChannelStore, Timestamp, UserStore, useStateFromStores } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
import overlayStyle from "./deleteStyleOverlay.css?managed";
|
||||
|
@ -43,7 +43,6 @@ interface MLMessage extends Message {
|
|||
}
|
||||
|
||||
const styles = findByPropsLazy("edited", "communicationDisabled", "isSystemMessage");
|
||||
const getMessage = findByCodeLazy('replace(/^\\n+|\\n+$/g,"")');
|
||||
|
||||
function addDeleteStyle() {
|
||||
if (Settings.plugins.MessageLogger.deleteStyle === "text") {
|
||||
|
@ -178,7 +177,7 @@ export default definePlugin({
|
|||
isEdited={true}
|
||||
isInline={false}
|
||||
>
|
||||
<span className={styles.edited}>{" "}({i18n.Messages.MESSAGE_EDITED})</span>
|
||||
<span className={styles.edited}>{" "}({getIntlMessage("MESSAGE_EDITED")})</span>
|
||||
</Timestamp>
|
||||
</div>
|
||||
))}
|
||||
|
@ -312,9 +311,33 @@ export default definePlugin({
|
|||
);
|
||||
},
|
||||
|
||||
Messages: proxyLazy(() => ({
|
||||
DELETED_MESSAGE_COUNT: getMessage("{count, plural, =0 {No deleted messages} one {{count} deleted message} other {{count} deleted messages}}")
|
||||
})),
|
||||
// DELETED_MESSAGE_COUNT: getMessage("{count, plural, =0 {No deleted messages} one {{count} deleted message} other {{count} deleted messages}}")
|
||||
// TODO: Find a better way to generate intl messages
|
||||
DELETED_MESSAGE_COUNT: () => ({
|
||||
ast: [[
|
||||
6,
|
||||
"count",
|
||||
{
|
||||
"=0": ["No deleted messages"],
|
||||
one: [
|
||||
[
|
||||
1,
|
||||
"count"
|
||||
],
|
||||
" deleted message"
|
||||
],
|
||||
other: [
|
||||
[
|
||||
1,
|
||||
"count"
|
||||
],
|
||||
" deleted messages"
|
||||
]
|
||||
},
|
||||
0,
|
||||
"cardinal"
|
||||
]]
|
||||
}),
|
||||
|
||||
patches: [
|
||||
{
|
||||
|
@ -323,35 +346,35 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
// Add deleted=true to all target messages in the MESSAGE_DELETE event
|
||||
match: /function (?=.+?MESSAGE_DELETE:(\i))\1\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?}(?=function)/,
|
||||
match: /MESSAGE_DELETE:function\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?},/,
|
||||
replace:
|
||||
"function $1($2){" +
|
||||
" var cache = $3getOrCreate($2.channelId);" +
|
||||
" cache = $self.handleDelete(cache, $2, false);" +
|
||||
" $3commit(cache);" +
|
||||
"}"
|
||||
"MESSAGE_DELETE:function($1){" +
|
||||
" var cache = $2getOrCreate($1.channelId);" +
|
||||
" cache = $self.handleDelete(cache, $1, false);" +
|
||||
" $2commit(cache);" +
|
||||
"},"
|
||||
},
|
||||
{
|
||||
// Add deleted=true to all target messages in the MESSAGE_DELETE_BULK event
|
||||
match: /function (?=.+?MESSAGE_DELETE_BULK:(\i))\1\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?}(?=function)/,
|
||||
match: /MESSAGE_DELETE_BULK:function\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?},/,
|
||||
replace:
|
||||
"function $1($2){" +
|
||||
" var cache = $3getOrCreate($2.channelId);" +
|
||||
" cache = $self.handleDelete(cache, $2, true);" +
|
||||
" $3commit(cache);" +
|
||||
"}"
|
||||
"MESSAGE_DELETE_BULK:function($1){" +
|
||||
" var cache = $2getOrCreate($1.channelId);" +
|
||||
" cache = $self.handleDelete(cache, $1, true);" +
|
||||
" $2commit(cache);" +
|
||||
"},"
|
||||
},
|
||||
{
|
||||
// Add current cached content + new edit time to cached message's editHistory
|
||||
match: /(function (\i)\((\i)\).+?)\.update\((\i)(?=.*MESSAGE_UPDATE:\2)/,
|
||||
match: /(MESSAGE_UPDATE:function\((\i)\).+?)\.update\((\i)/,
|
||||
replace: "$1" +
|
||||
".update($4,m =>" +
|
||||
" (($3.message.flags & 64) === 64 || $self.shouldIgnore($3.message, true)) ? m :" +
|
||||
" $3.message.edited_timestamp && $3.message.content !== m.content ?" +
|
||||
" m.set('editHistory',[...(m.editHistory || []), $self.makeEdit($3.message, m)]) :" +
|
||||
".update($3,m =>" +
|
||||
" (($2.message.flags & 64) === 64 || $self.shouldIgnore($2.message, true)) ? m :" +
|
||||
" $2.message.edited_timestamp && $2.message.content !== m.content ?" +
|
||||
" m.set('editHistory',[...(m.editHistory || []), $self.makeEdit($2.message, m)]) :" +
|
||||
" m" +
|
||||
")" +
|
||||
".update($4"
|
||||
".update($3"
|
||||
},
|
||||
{
|
||||
// fix up key (edit last message) attempting to edit a deleted message
|
||||
|
@ -445,7 +468,7 @@ export default definePlugin({
|
|||
|
||||
{
|
||||
// Message content renderer
|
||||
find: "Messages.MESSAGE_EDITED,\")\"",
|
||||
find: "#{intl::MESSAGE_EDITED}",
|
||||
replacement: [
|
||||
{
|
||||
// Render editHistory in the deepest div for message content
|
||||
|
@ -465,12 +488,12 @@ export default definePlugin({
|
|||
find: '"ReferencedMessageStore"',
|
||||
replacement: [
|
||||
{
|
||||
match: /MESSAGE_DELETE:\i,/,
|
||||
replace: "MESSAGE_DELETE:()=>{},"
|
||||
match: /MESSAGE_DELETE:function\((\i)\).+?},/,
|
||||
replace: "MESSAGE_DELETE:function($1){},"
|
||||
},
|
||||
{
|
||||
match: /MESSAGE_DELETE_BULK:\i,/,
|
||||
replace: "MESSAGE_DELETE_BULK:()=>{},"
|
||||
match: /MESSAGE_DELETE_BULK:function\((\i)\).+?},/,
|
||||
replace: "MESSAGE_DELETE_BULK:function($1){},"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -497,7 +520,7 @@ export default definePlugin({
|
|||
},
|
||||
{
|
||||
// Message group rendering
|
||||
find: "Messages.NEW_MESSAGES_ESTIMATED_WITH_DATE",
|
||||
find: "#{intl::NEW_MESSAGES_ESTIMATED_WITH_DATE}",
|
||||
replacement: [
|
||||
{
|
||||
match: /(\i).type===\i\.\i\.MESSAGE_GROUP_BLOCKED\|\|/,
|
||||
|
@ -505,7 +528,7 @@ export default definePlugin({
|
|||
},
|
||||
{
|
||||
match: /(\i).type===\i\.\i\.MESSAGE_GROUP_BLOCKED\?.*?:/,
|
||||
replace: '$&$1.type==="MESSAGE_GROUP_DELETED"?$self.Messages.DELETED_MESSAGE_COUNT:',
|
||||
replace: '$&$1.type==="MESSAGE_GROUP_DELETED"?$self.DELETED_MESSAGE_COUNT:',
|
||||
},
|
||||
],
|
||||
predicate: () => Settings.plugins.MessageLogger.collapseDeleted
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { Margins } from "@utils/margins";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByCodeLazy, findLazy } from "@webpack";
|
||||
|
@ -182,18 +183,18 @@ export default definePlugin({
|
|||
{
|
||||
find: ".ORIGINAL_POSTER=",
|
||||
replacement: {
|
||||
match: /(\i)=\{\}\)\);(?=let \i=100)/,
|
||||
replace: "$1=$self.getTagTypes()));"
|
||||
match: /\((\i)=\{\}\)\)\[(\i)\.BOT/,
|
||||
replace: "($1=$self.getTagTypes()))[$2.BOT"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: ".DISCORD_SYSTEM_MESSAGE_BOT_TAG_TOOLTIP_OFFICIAL,",
|
||||
find: "#{intl::DISCORD_SYSTEM_MESSAGE_BOT_TAG_TOOLTIP_OFFICIAL}",
|
||||
replacement: [
|
||||
// make the tag show the right text
|
||||
{
|
||||
match: /(switch\((\i)\){.+?)case (\i(?:\.\i)?)\.BOT:default:(\i)=.{0,40}(\i\.\i\.Messages)\.APP_TAG/,
|
||||
replace: (_, origSwitch, variant, tags, displayedText, strings) =>
|
||||
`${origSwitch}default:{${displayedText} = $self.getTagText(${tags}[${variant}], ${strings})}`
|
||||
match: /(switch\((\i)\){.+?)case (\i(?:\.\i)?)\.BOT:default:(\i)=(.{0,40}#{intl::APP_TAG}\))/,
|
||||
replace: (_, origSwitch, variant, tags, displayedText, originalText) =>
|
||||
`${origSwitch}default:{${displayedText} = $self.getTagText(${tags}[${variant}],${originalText})}`
|
||||
},
|
||||
// show OP tags correctly
|
||||
{
|
||||
|
@ -217,7 +218,7 @@ export default definePlugin({
|
|||
},
|
||||
// in the member list
|
||||
{
|
||||
find: ".Messages.GUILD_OWNER,",
|
||||
find: "#{intl::GUILD_OWNER}",
|
||||
replacement: {
|
||||
match: /(?<type>\i)=\(null==.{0,100}\.BOT;return null!=(?<user>\i)&&\i\.bot/,
|
||||
replace: "$<type> = $self.getTag({user: $<user>, channel: arguments[0].channel, origType: $<user>.bot ? 0 : null, location: 'not-chat' }); return typeof $<type> === 'number'"
|
||||
|
@ -232,7 +233,7 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: ".Messages.USER_PROFILE_PRONOUNS",
|
||||
find: "#{intl::USER_PROFILE_PRONOUNS}",
|
||||
replacement: {
|
||||
match: /(?=,hideBotTag:!0)/,
|
||||
replace: ",moreTags_channelId:arguments[0].moreTags_channelId"
|
||||
|
@ -295,21 +296,25 @@ export default definePlugin({
|
|||
|
||||
isOPTag: (tag: number) => tag === Tag.Types.ORIGINAL_POSTER || tags.some(t => tag === Tag.Types[`${t.name}-OP`]),
|
||||
|
||||
getTagText(passedTagName: string, strings: Record<string, string>) {
|
||||
if (!passedTagName) return strings.APP_TAG;
|
||||
const [tagName, variant] = passedTagName.split("-");
|
||||
const tag = tags.find(({ name }) => tagName === name);
|
||||
if (!tag) return strings.APP_TAG;
|
||||
if (variant === "BOT" && tagName !== "WEBHOOK" && this.settings.store.dontShowForBots) return strings.APP_TAG;
|
||||
getTagText(passedTagName: string, originalText: string) {
|
||||
try {
|
||||
const [tagName, variant] = passedTagName.split("-");
|
||||
if (!passedTagName) return getIntlMessage("APP_TAG");
|
||||
const tag = tags.find(({ name }) => tagName === name);
|
||||
if (!tag) return getIntlMessage("APP_TAG");
|
||||
if (variant === "BOT" && tagName !== "WEBHOOK" && this.settings.store.dontShowForBots) return getIntlMessage("APP_TAG");
|
||||
|
||||
const tagText = settings.store.tagSettings?.[tag.name]?.text || tag.displayName;
|
||||
switch (variant) {
|
||||
case "OP":
|
||||
return `${strings.BOT_TAG_FORUM_ORIGINAL_POSTER} • ${tagText}`;
|
||||
case "BOT":
|
||||
return `${strings.APP_TAG} • ${tagText}`;
|
||||
default:
|
||||
return tagText;
|
||||
const tagText = settings.store.tagSettings?.[tag.name]?.text || tag.displayName;
|
||||
switch (variant) {
|
||||
case "OP":
|
||||
return `${getIntlMessage("BOT_TAG_FORUM_ORIGINAL_POSTER")} • ${tagText}`;
|
||||
case "BOT":
|
||||
return `${getIntlMessage("APP_TAG")} • ${tagText}`;
|
||||
default:
|
||||
return tagText;
|
||||
}
|
||||
} catch {
|
||||
return originalText;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ const SelectedChannelActionCreators = findByPropsLazy("selectPrivateChannel");
|
|||
const UserUtils = findByPropsLazy("getGlobalName");
|
||||
|
||||
const ProfileListClasses = findByPropsLazy("emptyIconFriends", "emptyIconGuilds");
|
||||
const ExpandableList = findComponentByCodeLazy(".mutualFriendItem]");
|
||||
const ExpandableList = findComponentByCodeLazy('"PRESS_SECTION"');
|
||||
const GuildLabelClasses = findByPropsLazy("guildNick", "guildAvatarWithoutIcon");
|
||||
|
||||
function getGroupDMName(channel: Channel) {
|
||||
|
@ -142,16 +142,15 @@ export default definePlugin({
|
|||
const mutualGDms = getMutualGroupDms(user.id);
|
||||
if (mutualGDms.length === 0) return null;
|
||||
|
||||
const header = getMutualGDMCountText(user);
|
||||
|
||||
return (
|
||||
<>
|
||||
{Divider}
|
||||
<ExpandableList
|
||||
className={listStyle}
|
||||
header={header}
|
||||
isLoadingHeader={false}
|
||||
children={renderClickableGDMs(mutualGDms, () => { })}
|
||||
listClassName={listStyle}
|
||||
header={"Mutual Groups"}
|
||||
isLoading={false}
|
||||
items={renderClickableGDMs(mutualGDms, () => { })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -18,37 +18,44 @@
|
|||
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { runtimeHashMessageKey } from "@utils/intlHash";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { i18n } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
|
||||
|
||||
interface MessageDeleteProps {
|
||||
// Internal intl message for BLOCKED_MESSAGE_COUNT
|
||||
collapsedReason: () => any;
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "NoBlockedMessages",
|
||||
description: "Hides all blocked messages from chat completely.",
|
||||
authors: [Devs.rushii, Devs.Samu],
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.BLOCKED_MESSAGES_HIDE",
|
||||
find: "#{intl::BLOCKED_MESSAGES_HIDE}",
|
||||
replacement: [
|
||||
{
|
||||
match: /let\{[^}]*collapsedReason[^}]*\}/,
|
||||
replace: "return null;$&"
|
||||
replace: "if($self.shouldHide(arguments[0]))return null;$&"
|
||||
}
|
||||
]
|
||||
},
|
||||
...[
|
||||
'"MessageStore"',
|
||||
'"displayName","ReadStateStore")'
|
||||
'"ReadStateStore"'
|
||||
].map(find => ({
|
||||
find,
|
||||
predicate: () => Settings.plugins.NoBlockedMessages.ignoreBlockedMessages === true,
|
||||
replacement: [
|
||||
{
|
||||
match: /(?<=function (\i)\((\i)\){)(?=.*MESSAGE_CREATE:\1)/,
|
||||
replace: (_, _funcName, props) => `if($self.isBlocked(${props}.message))return;`
|
||||
match: /(?<=MESSAGE_CREATE:function\((\i)\){)/,
|
||||
replace: (_, props) => `if($self.isBlocked(${props}.message))return;`
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
@ -68,5 +75,14 @@ export default definePlugin({
|
|||
} catch (e) {
|
||||
new Logger("NoBlockedMessages").error("Failed to check if user is blocked:", e);
|
||||
}
|
||||
},
|
||||
|
||||
shouldHide(props: MessageDeleteProps) {
|
||||
try {
|
||||
return props.collapsedReason() === i18n.t[runtimeHashMessageKey("BLOCKED_MESSAGE_COUNT")]();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -20,7 +20,7 @@ const settings = definePluginSettings({
|
|||
export default definePlugin({
|
||||
name: "NoMosaic",
|
||||
authors: [Devs.AutumnVN],
|
||||
description: "Removes Discord new image mosaic",
|
||||
description: "Removes Discord image mosaic",
|
||||
tags: ["image", "mosaic", "media"],
|
||||
|
||||
settings,
|
||||
|
@ -29,8 +29,8 @@ export default definePlugin({
|
|||
{
|
||||
find: '=>"IMAGE"===',
|
||||
replacement: {
|
||||
match: /=>"IMAGE"===\i\|\|"VIDEO"===\i;/,
|
||||
replace: "=>false;"
|
||||
match: /=>"IMAGE"===\i\|\|"VIDEO"===\i(?:\|\|("VISUAL_PLACEHOLDER"===\i))?;/,
|
||||
replace: (_, visualPlaceholderPred) => visualPlaceholderPred != null ? `=>${visualPlaceholderPred};` : "=>false;"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ export default definePlugin({
|
|||
authors: [Devs.nekohaxx],
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.ONBOARDING_COVER_WELCOME_SUBTITLE",
|
||||
find: "#{intl::ONBOARDING_COVER_WELCOME_SUBTITLE}",
|
||||
replacement: {
|
||||
match: "3e3",
|
||||
replace: "0"
|
||||
|
|
|
@ -74,10 +74,10 @@ export default definePlugin({
|
|||
// This prevents the Message Requests tab from always hiding due to the previous patch (and is compatible with spam requests)
|
||||
// In short, only the red badge is hidden. Button visibility behavior isn't changed.
|
||||
{
|
||||
find: ".getSpamChannelsCount();",
|
||||
find: ".getSpamChannelsCount()",
|
||||
predicate: () => settings.store.hideMessageRequestsCount,
|
||||
replacement: {
|
||||
match: /(?<=getSpamChannelsCount\(\);return )\i\.getMessageRequestsCount\(\)/,
|
||||
match: /(?<=getSpamChannelsCount\(\),\i=)\i\.getMessageRequestsCount\(\)/,
|
||||
replace: "$self.getRealMessageRequestCount()"
|
||||
}
|
||||
},
|
||||
|
@ -87,7 +87,7 @@ export default definePlugin({
|
|||
replacement: {
|
||||
// The two groups inside the first group grab the minified names of the variables,
|
||||
// they are then referenced later to find unviewedTrialCount + unviewedDiscountCount.
|
||||
match: /(?<=\{unviewedTrialCount:(\i),unviewedDiscountCount:(\i)\}.{0,200}\i=)\1\+\2/,
|
||||
match: /(?<=\{unviewedTrialCount:(\i),unviewedDiscountCount:(\i)\}.{0,300}\i=)\1\+\2/,
|
||||
replace: "0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,21 +28,21 @@ export default definePlugin({
|
|||
{
|
||||
find: '.id,"Search Results"',
|
||||
replacement: {
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}UNBLOCK_TO_JUMP_TITLE)/,
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}#{intl::UNBLOCK_TO_JUMP_TITLE})/,
|
||||
replace: "if(false)$1"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "renderJumpButton()",
|
||||
replacement: {
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}UNBLOCK_TO_JUMP_TITLE)/,
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}#{intl::UNBLOCK_TO_JUMP_TITLE})/,
|
||||
replace: "if(false)$1"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "flash:!0,returnMessageId",
|
||||
replacement: {
|
||||
match: /.\?(.{1,10}\.show\({.{1,50}UNBLOCK_TO_JUMP_TITLE)/,
|
||||
match: /.\?(.{1,10}\.show\({.{1,50}#{intl::UNBLOCK_TO_JUMP_TITLE})/,
|
||||
replace: "false?$1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export default definePlugin({
|
|||
authors: [Devs.bb010g],
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.COPY_MESSAGE_LINK,",
|
||||
find: "#{intl::COPY_MESSAGE_LINK}",
|
||||
replacement: {
|
||||
match: /\.concat\(location\.host\)/,
|
||||
replace: ".concat($self.normalizeHost(location.host))",
|
||||
|
|
|
@ -87,19 +87,10 @@ export default definePlugin({
|
|||
{
|
||||
find: "trackAnnouncementMessageLinkClicked({",
|
||||
replacement: {
|
||||
match: /function (\i\(\i,\i\)\{)(?=.{0,100}trusted:)/,
|
||||
match: /function (\i\(\i,\i\)\{)(?=.{0,150}trusted:)/,
|
||||
replace: "async function $1 if(await $self.handleLink(...arguments)) return;"
|
||||
}
|
||||
},
|
||||
// Make Spotify profile activity links open in app on web
|
||||
{
|
||||
find: "WEB_OPEN(",
|
||||
predicate: () => !IS_DISCORD_DESKTOP && pluginSettings.store.spotify,
|
||||
replacement: {
|
||||
match: /\i\.\i\.isProtocolRegistered\(\)(.{0,100})window.open/g,
|
||||
replace: "true$1VencordNative.native.openExternal"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "no artist ids in metadata",
|
||||
predicate: () => !IS_DISCORD_DESKTOP && pluginSettings.store.spotify,
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Constants, GuildStore, i18n, RestAPI } from "@webpack/common";
|
||||
import { Constants, GuildStore, RestAPI } from "@webpack/common";
|
||||
|
||||
function showDisableInvites(guildId: string) {
|
||||
// @ts-ignore
|
||||
|
@ -43,15 +44,15 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION",
|
||||
find: "#{intl::GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION}",
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
match: /children:\i\.\i\.\i\.GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION/,
|
||||
match: /children:\i\.\i\.string\(\i\.\i#{intl::GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION}\)/,
|
||||
replace: "children: $self.renderInvitesLabel({guildId:arguments[0].guildId,setChecked})",
|
||||
},
|
||||
{
|
||||
match: /\.INVITES_DISABLED\)(?=.+?\.Messages\.INVITES_PERMANENTLY_DISABLED_TIP.+?checked:(\i)).+?\[\1,(\i)\]=\i.useState\(\i\)/,
|
||||
match: /\.INVITES_DISABLED\)(?=.+?#{intl::INVITES_PERMANENTLY_DISABLED_TIP}.+?checked:(\i)).+?\[\1,(\i)\]=\i.useState\(\i\)/,
|
||||
replace: "$&,setChecked=$2"
|
||||
}
|
||||
]
|
||||
|
@ -61,7 +62,7 @@ export default definePlugin({
|
|||
renderInvitesLabel: ErrorBoundary.wrap(({ guildId, setChecked }) => {
|
||||
return (
|
||||
<div>
|
||||
{i18n.Messages.GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION}
|
||||
{getIntlMessage("GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION")}
|
||||
{showDisableInvites(guildId) && <a role="button" onClick={() => {
|
||||
setChecked(true);
|
||||
disableInvites(guildId);
|
||||
|
|
|
@ -32,7 +32,7 @@ export default definePlugin({
|
|||
patches: [
|
||||
// Permission lockout, just set the check to true
|
||||
{
|
||||
find: ".STAGE_CHANNEL_CANNOT_OVERWRITE_PERMISSION",
|
||||
find: "#{intl::STAGE_CHANNEL_CANNOT_OVERWRITE_PERMISSION}",
|
||||
replacement: [
|
||||
{
|
||||
match: /case"DENY":.{0,50}if\((?=\i\.\i\.can)/,
|
||||
|
@ -43,7 +43,7 @@ export default definePlugin({
|
|||
},
|
||||
// Onboarding, same thing but we need to prevent the check
|
||||
{
|
||||
find: ".ONBOARDING_CHANNEL_THRESHOLD_WARNING",
|
||||
find: "#{intl::ONBOARDING_CHANNEL_THRESHOLD_WARNING}",
|
||||
replacement: [
|
||||
{
|
||||
match: /{(\i:function\(\){return \i},?){2}}/,
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { InfoIcon, OwnerCrownIcon } from "@components/Icons";
|
||||
import { getUniqueUsername } from "@utils/discord";
|
||||
import { getIntlMessage, getUniqueUsername } from "@utils/discord";
|
||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { findByCodeLazy } from "@webpack";
|
||||
import { Clipboard, ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildStore, i18n, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, UserStore, useState, useStateFromStores } from "@webpack/common";
|
||||
import { Clipboard, ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildStore, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, UserStore, useState, useStateFromStores } from "@webpack/common";
|
||||
import { UnicodeEmoji } from "@webpack/types";
|
||||
import type { Guild, Role, User } from "discord-types/general";
|
||||
|
||||
|
@ -216,7 +216,7 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str
|
|||
>
|
||||
<Menu.MenuItem
|
||||
id={cl("copy-role-id")}
|
||||
label={i18n.Messages.COPY_ID_ROLE}
|
||||
label={getIntlMessage("COPY_ID_ROLE")}
|
||||
action={() => {
|
||||
Clipboard.copy(roleId);
|
||||
}}
|
||||
|
@ -225,7 +225,7 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str
|
|||
{(settings.store as any).unsafeViewAsRole && (
|
||||
<Menu.MenuItem
|
||||
id={cl("view-as-role")}
|
||||
label={i18n.Messages.VIEW_AS_ROLE}
|
||||
label={getIntlMessage("VIEW_AS_ROLE")}
|
||||
action={() => {
|
||||
const role = GuildStore.getRole(guild.id, roleId);
|
||||
if (!role) return;
|
||||
|
@ -257,7 +257,7 @@ function UserContextMenu({ userId }: { userId: string; }) {
|
|||
>
|
||||
<Menu.MenuItem
|
||||
id={cl("copy-user-id")}
|
||||
label={i18n.Messages.COPY_ID_USER}
|
||||
label={getIntlMessage("COPY_ID_USER")}
|
||||
action={() => {
|
||||
Clipboard.copy(userId);
|
||||
}}
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { ExpandableHeader } from "@components/ExpandableHeader";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { classes } from "@utils/misc";
|
||||
import { filters, findBulk, proxyLazyWebpack } from "@webpack";
|
||||
import { i18n, PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/common";
|
||||
import { PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/common";
|
||||
import type { Guild, GuildMember } from "discord-types/general";
|
||||
|
||||
import { PermissionsSortOrder, settings } from "..";
|
||||
|
@ -105,7 +106,7 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
|
|||
permissions: Object.values(PermissionsBits).reduce((prev, curr) => prev | curr, 0n)
|
||||
});
|
||||
|
||||
const OWNER = i18n.Messages.GUILD_OWNER || "Server Owner";
|
||||
const OWNER = getIntlMessage("GUILD_OWNER") || "Server Owner";
|
||||
userPermissions.push({
|
||||
permission: OWNER,
|
||||
roleName: "Owner",
|
||||
|
|
|
@ -170,9 +170,9 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".VIEW_ALL_ROLES,",
|
||||
find: "#{intl::VIEW_ALL_ROLES}",
|
||||
replacement: {
|
||||
match: /\.collapseButton,.+?}\)}\),/,
|
||||
match: /\.expandButton,.+?null,/,
|
||||
replace: "$&$self.ViewPermissionsButton(arguments[0]),"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
*/
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { wordsToTitle } from "@utils/text";
|
||||
import { GuildStore, i18n, Parser } from "@webpack/common";
|
||||
import { GuildStore, Parser } from "@webpack/common";
|
||||
import { Guild, GuildMember, Role } from "discord-types/general";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
|
@ -44,7 +45,7 @@ const PermissionKeyMap = {
|
|||
export function getPermissionString(permission: string) {
|
||||
permission = PermissionKeyMap[permission] || permission;
|
||||
|
||||
return i18n.Messages[permission] ||
|
||||
return getIntlMessage(permission) ||
|
||||
// shouldn't get here but just in case
|
||||
formatPermissionWithoutMatchingString(permission);
|
||||
}
|
||||
|
@ -58,7 +59,7 @@ export function getPermissionDescription(permission: string): ReactNode {
|
|||
else if (permission !== "STREAM")
|
||||
permission = PermissionKeyMap[permission] || permission;
|
||||
|
||||
const msg = i18n.Messages[`ROLE_PERMISSIONS_${permission}_DESCRIPTION`] as any;
|
||||
const msg = getIntlMessage(`ROLE_PERMISSIONS_${permission}_DESCRIPTION`) as any;
|
||||
if (msg?.hasMarkdown)
|
||||
return Parser.parse(msg.message);
|
||||
|
||||
|
|
|
@ -30,10 +30,10 @@ export default definePlugin({
|
|||
{
|
||||
find: ".removeMosaicItemHoverButton),",
|
||||
replacement: {
|
||||
match: /\.nonMediaMosaicItem\]:!(\i).{0,50}?children:\[\S,(\S)/,
|
||||
replace: "$&,$1&&$2&&$self.renderPiPButton(),"
|
||||
},
|
||||
},
|
||||
match: /\.nonMediaMosaicItem\]:.{0,40}children:\[(?<=showDownload:(\i).+?isVisualMediaType:(\i).+?)/,
|
||||
replace: "$&$1&&$2&&$self.renderPiPButton(),"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
renderPiPButton: ErrorBoundary.wrap(() => {
|
||||
|
|
|
@ -30,7 +30,7 @@ interface ColorPickerWithSwatchesProps {
|
|||
renderCustomButton?: () => React.ReactNode;
|
||||
}
|
||||
|
||||
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
||||
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", ".BACKGROUND_PRIMARY)");
|
||||
const ColorPickerWithSwatches = findExportedComponentLazy<ColorPickerWithSwatchesProps>("ColorPicker", "CustomColorPicker");
|
||||
|
||||
export const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}Promise\.all\((\[\i\.\i\("?.+?"?\).+?\])\).then\(\i\.bind\(\i,"?(.+?)"?\)\).{0,50}"UserSettings"/);
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { findStoreLazy } from "@webpack";
|
||||
import { UserProfileStore, UserStore } from "@webpack/common";
|
||||
|
||||
import { settings } from "./settings";
|
||||
import { PronounMapping, Pronouns, PronounsCache, PronounSets, PronounsFormat, PronounSource, PronounsResponse } from "./types";
|
||||
|
||||
const UserSettingsAccountStore = findStoreLazy("UserSettingsAccountStore");
|
||||
|
||||
const EmptyPronouns = { pronouns: undefined, source: "", hasPendingPronouns: false } as const satisfies Pronouns;
|
||||
|
||||
type RequestCallback = (pronounSets?: PronounSets) => void;
|
||||
|
||||
const pronounCache: Record<string, PronounsCache> = {};
|
||||
const requestQueue: Record<string, RequestCallback[]> = {};
|
||||
let isProcessing = false;
|
||||
|
||||
async function processQueue() {
|
||||
if (isProcessing) return;
|
||||
isProcessing = true;
|
||||
|
||||
let ids = Object.keys(requestQueue);
|
||||
while (ids.length > 0) {
|
||||
const idsChunk = ids.splice(0, 50);
|
||||
const pronouns = await bulkFetchPronouns(idsChunk);
|
||||
|
||||
for (const id of idsChunk) {
|
||||
const callbacks = requestQueue[id];
|
||||
for (const callback of callbacks) {
|
||||
callback(pronouns[id]?.sets);
|
||||
}
|
||||
|
||||
delete requestQueue[id];
|
||||
}
|
||||
|
||||
ids = Object.keys(requestQueue);
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
}
|
||||
|
||||
isProcessing = false;
|
||||
}
|
||||
|
||||
function fetchPronouns(id: string): Promise<string | undefined> {
|
||||
return new Promise(resolve => {
|
||||
if (pronounCache[id] != null) {
|
||||
resolve(extractPronouns(pronounCache[id].sets));
|
||||
return;
|
||||
}
|
||||
|
||||
function handlePronouns(pronounSets?: PronounSets) {
|
||||
const pronouns = extractPronouns(pronounSets);
|
||||
resolve(pronouns);
|
||||
}
|
||||
|
||||
if (requestQueue[id] != null) {
|
||||
requestQueue[id].push(handlePronouns);
|
||||
return;
|
||||
}
|
||||
|
||||
requestQueue[id] = [handlePronouns];
|
||||
processQueue();
|
||||
});
|
||||
}
|
||||
|
||||
async function bulkFetchPronouns(ids: string[]): Promise<PronounsResponse> {
|
||||
const params = new URLSearchParams();
|
||||
params.append("platform", "discord");
|
||||
params.append("ids", ids.join(","));
|
||||
|
||||
try {
|
||||
const req = await fetch("https://pronoundb.org/api/v2/lookup?" + String(params), {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"X-PronounDB-Source": "WebExtension/0.14.5"
|
||||
}
|
||||
});
|
||||
|
||||
if (!req.ok) throw new Error(`Status ${req.status}`);
|
||||
const res: PronounsResponse = await req.json();
|
||||
|
||||
Object.assign(pronounCache, res);
|
||||
return res;
|
||||
|
||||
} catch (e) {
|
||||
console.error("PronounDB request failed:", e);
|
||||
const dummyPronouns: PronounsResponse = Object.fromEntries(ids.map(id => [id, { sets: {} }]));
|
||||
|
||||
Object.assign(pronounCache, dummyPronouns);
|
||||
return dummyPronouns;
|
||||
}
|
||||
}
|
||||
|
||||
function extractPronouns(pronounSets?: PronounSets): string | undefined {
|
||||
if (pronounSets == null) return undefined;
|
||||
if (pronounSets.en == null) return PronounMapping.unspecified;
|
||||
|
||||
const pronouns = pronounSets.en;
|
||||
if (pronouns.length === 0) return PronounMapping.unspecified;
|
||||
|
||||
const { pronounsFormat } = settings.store;
|
||||
|
||||
if (pronouns.length > 1) {
|
||||
const pronounString = pronouns.map(p => p[0].toUpperCase() + p.slice(1)).join("/");
|
||||
return pronounsFormat === PronounsFormat.Capitalized ? pronounString : pronounString.toLowerCase();
|
||||
}
|
||||
|
||||
const pronoun = pronouns[0];
|
||||
// For capitalized pronouns or special codes (any, ask, avoid), we always return the normal (capitalized) string
|
||||
if (pronounsFormat === PronounsFormat.Capitalized || ["any", "ask", "avoid", "other", "unspecified"].includes(pronoun)) {
|
||||
return PronounMapping[pronoun];
|
||||
} else {
|
||||
return PronounMapping[pronoun].toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
function getDiscordPronouns(id: string, useGlobalProfile: boolean = false): string | undefined {
|
||||
const globalPronouns = UserProfileStore.getUserProfile(id)?.pronouns;
|
||||
if (useGlobalProfile) return globalPronouns;
|
||||
|
||||
return UserProfileStore.getGuildMemberProfile(id, getCurrentChannel()?.guild_id)?.pronouns || globalPronouns;
|
||||
}
|
||||
|
||||
export function useFormattedPronouns(id: string, useGlobalProfile: boolean = false): Pronouns {
|
||||
const discordPronouns = getDiscordPronouns(id, useGlobalProfile)?.trim().replace(/\n+/g, "");
|
||||
const hasPendingPronouns = UserSettingsAccountStore.getPendingPronouns() != null;
|
||||
|
||||
const [pronouns] = useAwaiter(() => fetchPronouns(id));
|
||||
|
||||
if (settings.store.pronounSource === PronounSource.PreferDiscord && discordPronouns) {
|
||||
return { pronouns: discordPronouns, source: "Discord", hasPendingPronouns };
|
||||
}
|
||||
|
||||
if (pronouns != null && pronouns !== PronounMapping.unspecified) {
|
||||
return { pronouns, source: "PronounDB", hasPendingPronouns };
|
||||
}
|
||||
|
||||
return { pronouns: discordPronouns, source: "Discord", hasPendingPronouns };
|
||||
}
|
||||
|
||||
export function useProfilePronouns(id: string, useGlobalProfile: boolean = false): Pronouns {
|
||||
try {
|
||||
const pronouns = useFormattedPronouns(id, useGlobalProfile);
|
||||
|
||||
if (!settings.store.showInProfile) return EmptyPronouns;
|
||||
if (!settings.store.showSelf && id === UserStore.getCurrentUser()?.id) return EmptyPronouns;
|
||||
|
||||
return pronouns;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return EmptyPronouns;
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Link } from "@components/Link";
|
||||
import { Forms, React } from "@webpack/common";
|
||||
|
||||
export default function PronounsAboutComponent() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Forms.FormTitle tag="h3">More Information</Forms.FormTitle>
|
||||
<Forms.FormText>To add your own pronouns, visit{" "}
|
||||
<Link href="https://pronoundb.org">pronoundb.org</Link>
|
||||
</Forms.FormText>
|
||||
<Forms.FormDivider />
|
||||
<Forms.FormText>
|
||||
The two pronoun formats are lowercase and capitalized. Example:
|
||||
<ul>
|
||||
<li>Lowercase: they/them</li>
|
||||
<li>Capitalized: They/Them</li>
|
||||
</ul>
|
||||
Text like "Ask me my pronouns" or "Any pronouns" will always be capitalized. <br /><br />
|
||||
You can also configure whether or not to display pronouns for the current user (since you probably already know them)
|
||||
</Forms.FormText>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
import { useProfilePronouns } from "./api";
|
||||
import PronounsAboutComponent from "./components/PronounsAboutComponent";
|
||||
import { CompactPronounsChatComponentWrapper, PronounsChatComponentWrapper } from "./components/PronounsChatComponent";
|
||||
import { settings } from "./settings";
|
||||
|
||||
export default definePlugin({
|
||||
name: "PronounDB",
|
||||
authors: [Devs.Tyman, Devs.TheKodeToad, Devs.Ven, Devs.Elvyra],
|
||||
description: "Adds pronouns to user messages using pronoundb",
|
||||
patches: [
|
||||
{
|
||||
find: "showCommunicationDisabledStyles",
|
||||
replacement: [
|
||||
// Add next to username (compact mode)
|
||||
{
|
||||
match: /("span",{id:\i,className:\i,children:\i}\))/,
|
||||
replace: "$1, $self.CompactPronounsChatComponentWrapper(arguments[0])"
|
||||
},
|
||||
// Patch the chat timestamp element (normal mode)
|
||||
{
|
||||
match: /(?<=return\s*\(0,\i\.jsxs?\)\(.+!\i&&)(\(0,\i.jsxs?\)\(.+?\{.+?\}\))/,
|
||||
replace: "[$1, $self.PronounsChatComponentWrapper(arguments[0])]"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
find: ".Messages.USER_PROFILE_PRONOUNS",
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
match: /\.PANEL},/,
|
||||
replace: "$&{pronouns:vcPronoun,source:vcPronounSource,hasPendingPronouns:vcHasPendingPronouns}=$self.useProfilePronouns(arguments[0].user?.id),"
|
||||
},
|
||||
{
|
||||
match: /text:\i\.\i.Messages.USER_PROFILE_PRONOUNS/,
|
||||
replace: '$&+(vcPronoun==null||vcHasPendingPronouns?"":` (${vcPronounSource})`)'
|
||||
},
|
||||
{
|
||||
match: /(\.pronounsText.+?children:)(\i)/,
|
||||
replace: "$1(vcPronoun==null||vcHasPendingPronouns)?$2:vcPronoun"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
settings,
|
||||
|
||||
settingsAboutComponent: PronounsAboutComponent,
|
||||
|
||||
// Re-export the components on the plugin object so it is easily accessible in patches
|
||||
PronounsChatComponentWrapper,
|
||||
CompactPronounsChatComponentWrapper,
|
||||
useProfilePronouns
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
.vc-pronoundb-compact {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[class*="compact"] .vc-pronoundb-compact {
|
||||
display: inline-block;
|
||||
margin-left: -2px;
|
||||
margin-right: 0.25rem;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface UserProfileProps {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface UserProfilePronounsProps {
|
||||
currentPronouns: string | null;
|
||||
hidePersonalInformation: boolean;
|
||||
}
|
||||
|
||||
export type PronounSets = Record<string, PronounCode[]>;
|
||||
export type PronounsResponse = Record<string, { sets?: PronounSets; }>;
|
||||
|
||||
export interface PronounsCache {
|
||||
sets?: PronounSets;
|
||||
}
|
||||
|
||||
export const PronounMapping = {
|
||||
he: "He/Him",
|
||||
it: "It/Its",
|
||||
she: "She/Her",
|
||||
they: "They/Them",
|
||||
any: "Any pronouns",
|
||||
other: "Other pronouns",
|
||||
ask: "Ask me my pronouns",
|
||||
avoid: "Avoid pronouns, use my name",
|
||||
unspecified: "No pronouns specified.",
|
||||
} as const satisfies Record<string, string>;
|
||||
|
||||
export type PronounCode = keyof typeof PronounMapping;
|
||||
|
||||
export interface Pronouns {
|
||||
pronouns?: string;
|
||||
source: string;
|
||||
hasPendingPronouns: boolean;
|
||||
}
|
||||
|
||||
export const enum PronounsFormat {
|
||||
Lowercase = "LOWERCASE",
|
||||
Capitalized = "CAPITALIZED"
|
||||
}
|
||||
|
||||
export const enum PronounSource {
|
||||
PreferPDB,
|
||||
PreferDiscord
|
||||
}
|
|
@ -50,6 +50,8 @@ async function runMigrations() {
|
|||
|
||||
export async function syncAndRunChecks() {
|
||||
await runMigrations();
|
||||
if (UserStore.getCurrentUser() == null) return;
|
||||
|
||||
const [oldGuilds, oldGroups, oldFriends] = await DataStore.getMany([
|
||||
guildsKey(),
|
||||
groupsKey(),
|
||||
|
|
|
@ -67,7 +67,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".REPLY_QUOTE_MESSAGE_BLOCKED",
|
||||
find: "#{intl::REPLY_QUOTE_MESSAGE_BLOCKED}",
|
||||
replacement: {
|
||||
match: /\.onClickReply,.+?}\),(?=\i,\i,\i\])/,
|
||||
replace: "$&$self.ReplyTimestamp(arguments[0]),"
|
||||
|
|
|
@ -108,7 +108,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.MESSAGE_ACTIONS_MENU_LABEL,shouldHideMediaOptions",
|
||||
find: "#{intl::MESSAGE_ACTIONS_MENU_LABEL}",
|
||||
replacement: {
|
||||
match: /favoriteableType:\i,(?<=(\i)\.getAttribute\("data-type"\).+?)/,
|
||||
replace: (m, target) => `${m}reverseImageSearchType:${target}.getAttribute("data-role"),`
|
||||
|
|
|
@ -20,6 +20,7 @@ import { definePluginSettings } from "@api/Settings";
|
|||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { makeRange } from "@components/PluginSettings/components";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByCodeLazy } from "@webpack";
|
||||
import { ChannelStore, GuildMemberStore, GuildStore } from "@webpack/common";
|
||||
|
@ -51,6 +52,12 @@ const settings = definePluginSettings({
|
|||
description: "Show role colors in the reactors list",
|
||||
restartNeeded: true
|
||||
},
|
||||
pollResults: {
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true,
|
||||
description: "Show role colors in the poll results",
|
||||
restartNeeded: true
|
||||
},
|
||||
colorChatMessages: {
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
|
@ -62,14 +69,15 @@ const settings = definePluginSettings({
|
|||
description: "Intensity of message coloring.",
|
||||
markers: makeRange(0, 100, 10),
|
||||
default: 30
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default definePlugin({
|
||||
name: "RoleColorEverywhere",
|
||||
authors: [Devs.KingFish, Devs.lewisakura, Devs.AutumnVN, Devs.Kyuuhachi],
|
||||
authors: [Devs.KingFish, Devs.lewisakura, Devs.AutumnVN, Devs.Kyuuhachi, Devs.jamesbt365],
|
||||
description: "Adds the top role color anywhere possible",
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
// Chat Mentions
|
||||
{
|
||||
|
@ -77,82 +85,133 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
match: /onContextMenu:\i,color:\i,\.\.\.\i(?=,children:)(?<=user:(\i),channel:(\i).{0,500}?)/,
|
||||
replace: "$&,color:$self.getUserColor($1?.id,{channelId:$2?.id})"
|
||||
replace: "$&,color:$self.getColorInt($1?.id,$2?.id)"
|
||||
}
|
||||
],
|
||||
predicate: () => settings.store.chatMentions,
|
||||
predicate: () => settings.store.chatMentions
|
||||
},
|
||||
// Slate
|
||||
{
|
||||
find: ".userTooltip,children",
|
||||
replacement: [
|
||||
{
|
||||
match: /let\{id:(\i),guildId:(\i)[^}]*\}.*?\.\i,{(?=children)/,
|
||||
replace: "$&color:$self.getUserColor($1,{guildId:$2}),"
|
||||
match: /let\{id:(\i),guildId:\i,channelId:(\i)[^}]*\}.*?\.\i,{(?=children)/,
|
||||
replace: "$&color:$self.getColorInt($1,$2),"
|
||||
}
|
||||
],
|
||||
predicate: () => settings.store.chatMentions,
|
||||
predicate: () => settings.store.chatMentions
|
||||
},
|
||||
// Member List Role Headers
|
||||
{
|
||||
find: 'tutorialId:"whos-online',
|
||||
replacement: [
|
||||
{
|
||||
match: /null,\i," — ",\i\]/,
|
||||
replace: "null,$self.roleGroupColor(arguments[0])]"
|
||||
replace: "null,$self.RoleGroupColor(arguments[0])]"
|
||||
},
|
||||
],
|
||||
predicate: () => settings.store.memberList,
|
||||
predicate: () => settings.store.memberList
|
||||
},
|
||||
{
|
||||
find: ".Messages.THREAD_BROWSER_PRIVATE",
|
||||
find: "#{intl::THREAD_BROWSER_PRIVATE}",
|
||||
replacement: [
|
||||
{
|
||||
match: /children:\[\i," — ",\i\]/,
|
||||
replace: "children:[$self.roleGroupColor(arguments[0])]"
|
||||
replace: "children:[$self.RoleGroupColor(arguments[0])]"
|
||||
},
|
||||
],
|
||||
predicate: () => settings.store.memberList,
|
||||
predicate: () => settings.store.memberList
|
||||
},
|
||||
// Voice Users
|
||||
{
|
||||
find: "renderPrioritySpeaker",
|
||||
find: "renderPrioritySpeaker(){",
|
||||
replacement: [
|
||||
{
|
||||
match: /renderName\(\){.+?usernameSpeaking\]:.+?(?=children)/,
|
||||
replace: "$&...$self.getVoiceProps(this.props),"
|
||||
replace: "$&style:$self.getColorStyle(this?.props?.user?.id,this?.props?.guildId),"
|
||||
}
|
||||
],
|
||||
predicate: () => settings.store.voiceUsers,
|
||||
predicate: () => settings.store.voiceUsers
|
||||
},
|
||||
// Reaction List
|
||||
{
|
||||
find: ".reactorDefault",
|
||||
replacement: {
|
||||
match: /,onContextMenu:e=>.{0,15}\((\i),(\i),(\i)\).{0,250}tag:"strong"/,
|
||||
replace: "$&,style:{color:$self.getColor($2?.id,$1)}"
|
||||
match: /,onContextMenu:\i=>.{0,15}\((\i),(\i),(\i)\).{0,250}tag:"strong"/,
|
||||
replace: "$&,style:$self.getColorStyle($2?.id,$1?.channel?.id)"
|
||||
},
|
||||
predicate: () => settings.store.reactorsList,
|
||||
},
|
||||
// Poll Results
|
||||
{
|
||||
find: '.Messages.MESSAGE_EDITED,")"',
|
||||
find: ",reactionVoteCounts",
|
||||
replacement: {
|
||||
match: /\.nickname,(?=children:)/,
|
||||
replace: "$&style:$self.getColorStyle(arguments[0]?.user?.id,arguments[0]?.channel?.id),"
|
||||
},
|
||||
predicate: () => settings.store.pollResults
|
||||
},
|
||||
// Messages
|
||||
{
|
||||
find: "#{intl::MESSAGE_EDITED}",
|
||||
replacement: {
|
||||
match: /(?<=isUnsupported\]:(\i)\.isUnsupported\}\),)(?=children:\[)/,
|
||||
replace: "style:{color:$self.useMessageColor($1)},"
|
||||
replace: "style:$self.useMessageColorStyle($1),"
|
||||
},
|
||||
predicate: () => settings.store.colorChatMessages,
|
||||
},
|
||||
predicate: () => settings.store.colorChatMessages
|
||||
}
|
||||
],
|
||||
settings,
|
||||
|
||||
getColor(userId: string, { channelId, guildId }: { channelId?: string; guildId?: string; }) {
|
||||
if (!(guildId ??= ChannelStore.getChannel(channelId!)?.guild_id)) return null;
|
||||
return GuildMemberStore.getMember(guildId, userId)?.colorString ?? null;
|
||||
getColorString(userId: string, channelOrGuildId: string) {
|
||||
try {
|
||||
const guildId = ChannelStore.getChannel(channelOrGuildId)?.guild_id ?? GuildStore.getGuild(channelOrGuildId)?.id;
|
||||
if (guildId == null) return null;
|
||||
|
||||
return GuildMemberStore.getMember(guildId, userId)?.colorString ?? null;
|
||||
} catch (e) {
|
||||
new Logger("RoleColorEverywhere").error("Failed to get color string", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getUserColor(userId: string, ids: { channelId?: string; guildId?: string; }) {
|
||||
const colorString = this.getColor(userId, ids);
|
||||
getColorInt(userId: string, channelOrGuildId: string) {
|
||||
const colorString = this.getColorString(userId, channelOrGuildId);
|
||||
return colorString && parseInt(colorString.slice(1), 16);
|
||||
},
|
||||
|
||||
roleGroupColor: ErrorBoundary.wrap(({ id, count, title, guildId, label }: { id: string; count: number; title: string; guildId: string; label: string; }) => {
|
||||
getColorStyle(userId: string, channelOrGuildId: string) {
|
||||
const colorString = this.getColorString(userId, channelOrGuildId);
|
||||
|
||||
return colorString && {
|
||||
color: colorString
|
||||
};
|
||||
},
|
||||
|
||||
useMessageColor(message: any) {
|
||||
try {
|
||||
const { messageSaturation } = settings.use(["messageSaturation"]);
|
||||
const author = useMessageAuthor(message);
|
||||
|
||||
if (author.colorString != null && messageSaturation !== 0) {
|
||||
return `color-mix(in oklab, ${author.colorString} ${messageSaturation}%, var(--text-normal))`;
|
||||
}
|
||||
} catch (e) {
|
||||
new Logger("RoleColorEverywhere").error("Failed to get message color", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
useMessageColorStyle(message: any) {
|
||||
const color = this.useMessageColor(message);
|
||||
|
||||
return color && {
|
||||
color
|
||||
};
|
||||
},
|
||||
|
||||
RoleGroupColor: ErrorBoundary.wrap(({ id, count, title, guildId, label }: { id: string; count: number; title: string; guildId: string; label: string; }) => {
|
||||
const role = GuildStore.getRole(guildId, id);
|
||||
|
||||
return (
|
||||
|
@ -164,25 +223,5 @@ export default definePlugin({
|
|||
{title ?? label} — {count}
|
||||
</span>
|
||||
);
|
||||
}, { noop: true }),
|
||||
|
||||
getVoiceProps({ user: { id: userId }, guildId }: { user: { id: string; }; guildId: string; }) {
|
||||
return {
|
||||
style: {
|
||||
color: this.getColor(userId, { guildId })
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
useMessageColor(message: any) {
|
||||
try {
|
||||
const { messageSaturation } = settings.use(["messageSaturation"]);
|
||||
const author = useMessageAuthor(message);
|
||||
if (author.colorString !== undefined && messageSaturation !== 0)
|
||||
return `color-mix(in oklab, ${author.colorString} ${messageSaturation}%, var(--text-normal))`;
|
||||
} catch (e) {
|
||||
console.error("[RCE] failed to get message color", e);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
}, { noop: true })
|
||||
});
|
||||
|
|
|
@ -80,7 +80,10 @@ function GuildInfoModal({ guild }: GuildProps) {
|
|||
className={cl("banner")}
|
||||
src={bannerUrl}
|
||||
alt=""
|
||||
onClick={() => openImageModal(bannerUrl)}
|
||||
onClick={() => openImageModal({
|
||||
url: bannerUrl,
|
||||
width: 1024
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -89,7 +92,11 @@ function GuildInfoModal({ guild }: GuildProps) {
|
|||
? <img
|
||||
src={iconUrl}
|
||||
alt=""
|
||||
onClick={() => openImageModal(iconUrl)}
|
||||
onClick={() => openImageModal({
|
||||
url: iconUrl,
|
||||
height: 512,
|
||||
width: 512,
|
||||
})}
|
||||
/>
|
||||
: <div aria-hidden className={classes(IconClasses.childWrapper, IconClasses.acronym)}>{guild.acronym}</div>
|
||||
}
|
||||
|
@ -151,7 +158,15 @@ function Owner(guildId: string, owner: User) {
|
|||
|
||||
return (
|
||||
<div className={cl("owner")}>
|
||||
<img src={ownerAvatarUrl} alt="" onClick={() => openImageModal(ownerAvatarUrl)} />
|
||||
<img
|
||||
src={ownerAvatarUrl}
|
||||
alt=""
|
||||
onClick={() => openImageModal({
|
||||
url: ownerAvatarUrl,
|
||||
height: 512,
|
||||
width: 512
|
||||
})}
|
||||
/>
|
||||
{Parser.parse(`<@${owner.id}>`)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -30,7 +30,9 @@ export default definePlugin({
|
|||
name: "ServerInfo",
|
||||
description: "Allows you to view info about a server",
|
||||
authors: [Devs.Ven, Devs.Nuckyz],
|
||||
dependencies: ["DynamicImageModalAPI"],
|
||||
tags: ["guild", "info", "ServerProfile"],
|
||||
|
||||
contextMenus: {
|
||||
"guild-context": Patch,
|
||||
"guild-header-popout": Patch
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,9 +18,9 @@
|
|||
|
||||
import { IShikiTheme } from "@vap/shiki";
|
||||
|
||||
export const SHIKI_REPO = "shikijs/shiki";
|
||||
export const SHIKI_REPO_COMMIT = "0b28ad8ccfbf2615f2d9d38ea8255416b8ac3043";
|
||||
export const shikiRepoTheme = (name: string) => `https://raw.githubusercontent.com/${SHIKI_REPO}/${SHIKI_REPO_COMMIT}/packages/shiki/themes/${name}.json`;
|
||||
export const SHIKI_REPO = "shikijs/textmate-grammars-themes";
|
||||
export const SHIKI_REPO_COMMIT = "2d87559c7601a928b9f7e0f0dda243d2fb6d4499";
|
||||
export const shikiRepoTheme = (name: string) => `https://raw.githubusercontent.com/${SHIKI_REPO}/${SHIKI_REPO_COMMIT}/packages/tm-themes/themes/${name}.json`;
|
||||
|
||||
export const themes = {
|
||||
// Default
|
||||
|
@ -30,33 +30,59 @@ export const themes = {
|
|||
MaterialCandy: "https://raw.githubusercontent.com/millsp/material-candy/master/material-candy.json",
|
||||
|
||||
// More from Shiki repo
|
||||
Andromeeda: shikiRepoTheme("andromeeda"),
|
||||
AuroraX: shikiRepoTheme("aurora-x"),
|
||||
AyuDark: shikiRepoTheme("ayu-dark"),
|
||||
CatppuccinLatte: shikiRepoTheme("catppuccin-latte"),
|
||||
CatppuccinFrappe: shikiRepoTheme("catppuccin-frappe"),
|
||||
CatppuccinMacchiato: shikiRepoTheme("catppuccin-macchiato"),
|
||||
CatppuccinMocha: shikiRepoTheme("catppuccin-mocha"),
|
||||
DraculaSoft: shikiRepoTheme("dracula-soft"),
|
||||
Dracula: shikiRepoTheme("dracula"),
|
||||
EverforestDark: shikiRepoTheme("everforest-dark"),
|
||||
EverforestLight: shikiRepoTheme("everforest-light"),
|
||||
GithubDarkDefault: shikiRepoTheme("github-dark-default"),
|
||||
GithubDarkDimmed: shikiRepoTheme("github-dark-dimmed"),
|
||||
GithubDarkHighContrast: shikiRepoTheme("github-dark-high-contrast"),
|
||||
GithubDark: shikiRepoTheme("github-dark"),
|
||||
GithubLightDefault: shikiRepoTheme("github-light-default"),
|
||||
GithubLightHighContrast: shikiRepoTheme("github-light-high-contrast"),
|
||||
GithubLight: shikiRepoTheme("github-light"),
|
||||
Houston: shikiRepoTheme("houston"),
|
||||
KanagawaDragon: shikiRepoTheme("kanagawa-dragon"),
|
||||
KanagawaLotus: shikiRepoTheme("kanagawa-lotus"),
|
||||
KanagawaWave: shikiRepoTheme("kanagawa-wave"),
|
||||
LaserWave: shikiRepoTheme("laserwave"),
|
||||
LightPlus: shikiRepoTheme("light-plus"),
|
||||
MaterialDarker: shikiRepoTheme("material-darker"),
|
||||
MaterialDefault: shikiRepoTheme("material-default"),
|
||||
MaterialLighter: shikiRepoTheme("material-lighter"),
|
||||
MaterialOcean: shikiRepoTheme("material-ocean"),
|
||||
MaterialPalenight: shikiRepoTheme("material-palenight"),
|
||||
MaterialDarker: shikiRepoTheme("material-theme-darker"),
|
||||
MaterialDefault: shikiRepoTheme("material-theme"),
|
||||
MaterialLighter: shikiRepoTheme("material-theme-lighter"),
|
||||
MaterialOcean: shikiRepoTheme("material-theme-ocean"),
|
||||
MaterialPalenight: shikiRepoTheme("material-theme-palenight"),
|
||||
MinDark: shikiRepoTheme("min-dark"),
|
||||
MinLight: shikiRepoTheme("min-light"),
|
||||
Monokai: shikiRepoTheme("monokai"),
|
||||
NightOwl: shikiRepoTheme("night-owl"),
|
||||
Nord: shikiRepoTheme("nord"),
|
||||
OneDarkPro: shikiRepoTheme("one-dark-pro"),
|
||||
OneLight: shikiRepoTheme("one-light"),
|
||||
Plastic: shikiRepoTheme("plastic"),
|
||||
Poimandres: shikiRepoTheme("poimandres"),
|
||||
Red: shikiRepoTheme("red"),
|
||||
RosePineDawn: shikiRepoTheme("rose-pine-dawn"),
|
||||
RosePineMoon: shikiRepoTheme("rose-pine-moon"),
|
||||
RosePine: shikiRepoTheme("rose-pine"),
|
||||
SlackDark: shikiRepoTheme("slack-dark"),
|
||||
SlackOchin: shikiRepoTheme("slack-ochin"),
|
||||
SnazzyLight: shikiRepoTheme("snazzy-light"),
|
||||
SolarizedDark: shikiRepoTheme("solarized-dark"),
|
||||
SolarizedLight: shikiRepoTheme("solarized-light"),
|
||||
Synthwave84: shikiRepoTheme("synthwave-84"),
|
||||
TokyoNight: shikiRepoTheme("tokyo-night"),
|
||||
Vesper: shikiRepoTheme("vesper"),
|
||||
VitesseBlack: shikiRepoTheme("vitesse-black"),
|
||||
VitesseDark: shikiRepoTheme("vitesse-dark"),
|
||||
VitesseLight: shikiRepoTheme("vitesse-light"),
|
||||
CssVariables: shikiRepoTheme("css-variables"),
|
||||
};
|
||||
|
||||
export const themeCache = new Map<string, IShikiTheme>();
|
||||
|
|
|
@ -46,7 +46,7 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: ".PREVIEW_NUM_LINES",
|
||||
find: "#{intl::PREVIEW_NUM_LINES}",
|
||||
replacement: {
|
||||
match: /(?<=function \i\((\i)\)\{)(?=let\{text:\i,language:)/,
|
||||
replace: "return $self.renderHighlighter({lang:$1.language,content:$1.text});"
|
||||
|
|
|
@ -26,7 +26,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.MESSAGE_UTILITIES_A11Y_LABEL",
|
||||
find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}",
|
||||
replacement: {
|
||||
match: /isExpanded:\i&&(.+?),/,
|
||||
replace: "isExpanded:$1,"
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { findComponentByCodeLazy, findLazy } from "@webpack";
|
||||
import { i18n, useToken } from "@webpack/common";
|
||||
import { useToken } from "@webpack/common";
|
||||
|
||||
const ColorMap = findLazy(m => m.colors?.INTERACTIVE_MUTED?.css);
|
||||
const VerifiedIconComponent = findComponentByCodeLazy(".CONNECTIONS_ROLE_OFFICIAL_ICON_TOOLTIP");
|
||||
const VerifiedIconComponent = findComponentByCodeLazy("#{intl::CONNECTIONS_ROLE_OFFICIAL_ICON_TOOLTIP}");
|
||||
|
||||
export function VerifiedIcon() {
|
||||
const color = useToken(ColorMap.colors.INTERACTIVE_MUTED).hex();
|
||||
|
@ -31,7 +32,7 @@ export function VerifiedIcon() {
|
|||
color={color}
|
||||
forcedIconColor={forcedIconColor}
|
||||
size={16}
|
||||
tooltipText={i18n.Messages.CONNECTION_VERIFIED}
|
||||
tooltipText={getIntlMessage("CONNECTION_VERIFIED")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import { Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { formatDuration } from "@utils/text";
|
||||
import { findByPropsLazy, findComponentByCodeLazy, findComponentLazy } from "@webpack";
|
||||
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
|
||||
import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common";
|
||||
import type { Channel } from "discord-types/general";
|
||||
|
||||
|
@ -80,14 +80,8 @@ const enum ChannelFlags {
|
|||
|
||||
const ChatScrollClasses = findByPropsLazy("auto", "managedReactiveScroller");
|
||||
const ChatClasses = findByPropsLazy("chat", "content", "noChat", "chatContent");
|
||||
const ChannelBeginHeader = findComponentByCodeLazy(".Messages.ROLE_REQUIRED_SINGLE_USER_MESSAGE");
|
||||
const TagComponent = findComponentLazy(m => {
|
||||
if (typeof m !== "function") return false;
|
||||
|
||||
const code = Function.prototype.toString.call(m);
|
||||
// Get the component which doesn't include increasedActivity
|
||||
return code.includes(".Messages.FORUM_TAG_A11Y_FILTER_BY_TAG") && !code.includes("increasedActivityPill");
|
||||
});
|
||||
const ChannelBeginHeader = findComponentByCodeLazy("#{intl::ROLE_REQUIRED_SINGLE_USER_MESSAGE}");
|
||||
const TagComponent = findComponentByCodeLazy("#{intl::FORUM_TAG_A11Y_FILTER_BY_TAG}");
|
||||
|
||||
const EmojiParser = findByPropsLazy("convertSurrogateToName");
|
||||
const EmojiUtils = findByPropsLazy("getURL", "getEmojiColors");
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue