mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-09 17:36:23 +00:00
Merge branch 'main' into main
This commit is contained in:
commit
3bb55d23f9
141 changed files with 1133 additions and 924 deletions
|
@ -31,6 +31,7 @@ Before starting your plugin:
|
|||
- No FakeDeafen or FakeMute
|
||||
- No StereoMic
|
||||
- No plugins that simply hide or redesign ui elements. This can be done with CSS
|
||||
- No plugins that interact with specific Discord bots (official Discord apps like Youtube WatchTogether are okay)
|
||||
- No selfbots or API spam (animated status, message pruner, auto reply, nitro snipers, etc)
|
||||
- No untrusted third party APIs. Popular services like Google or GitHub are fine, but absolutely no self hosted ones
|
||||
- No plugins that require the user to enter their own API key
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "vencord",
|
||||
"private": "true",
|
||||
"version": "1.10.5",
|
||||
"version": "1.10.9",
|
||||
"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])
|
||||
});
|
||||
|
||||
|
|
|
@ -99,7 +99,8 @@ export interface ChatBarButtonProps {
|
|||
tooltip: string;
|
||||
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||
onContextMenu?: MouseEventHandler<HTMLButtonElement>;
|
||||
buttonProps?: Omit<HTMLProps<HTMLButtonElement>, "size" | "onClick" | "onContextMenu">;
|
||||
onAuxClick?: MouseEventHandler<HTMLButtonElement>;
|
||||
buttonProps?: Omit<HTMLProps<HTMLButtonElement>, "size" | "onClick" | "onContextMenu" | "onAuxClick">;
|
||||
}
|
||||
export const ChatBarButton = ErrorBoundary.wrap((props: ChatBarButtonProps) => {
|
||||
return (
|
||||
|
@ -115,6 +116,7 @@ export const ChatBarButton = ErrorBoundary.wrap((props: ChatBarButtonProps) => {
|
|||
innerClassName={`${ButtonWrapperClasses.button} ${ChannelTextAreaClasses?.button}`}
|
||||
onClick={props.onClick}
|
||||
onContextMenu={props.onContextMenu}
|
||||
onAuxClick={props.onAuxClick}
|
||||
{...props.buttonProps}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
|
|
|
@ -54,5 +54,5 @@ export function sendBotMessage(channelId: string, message: PartialDeep<Message>)
|
|||
export function findOption<T>(args: Argument[], name: string): T & {} | undefined;
|
||||
export function findOption<T>(args: Argument[], name: string, fallbackValue: T): T & {};
|
||||
export function findOption(args: Argument[], name: string, fallbackValue?: any) {
|
||||
return (args.find(a => a.name === name)?.value || fallbackValue) as any;
|
||||
return (args.find(a => a.name === name)?.value ?? fallbackValue) as any;
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ function registerSubCommands(cmd: Command, plugin: string) {
|
|||
const subCmd = {
|
||||
...cmd,
|
||||
...o,
|
||||
options: o.options !== undefined ? o.options : undefined,
|
||||
type: ApplicationCommandType.CHAT_INPUT,
|
||||
name: `${cmd.name} ${o.name}`,
|
||||
id: `${o.name}-${cmd.id}`,
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
.vc-expandableheader-center-flex {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.vc-expandableheader-btn {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 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 "./ExpandableHeader.css";
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Text, Tooltip, useState } from "@webpack/common";
|
||||
|
||||
const cl = classNameFactory("vc-expandableheader-");
|
||||
|
||||
export interface ExpandableHeaderProps {
|
||||
onMoreClick?: () => void;
|
||||
moreTooltipText?: string;
|
||||
onDropDownClick?: (state: boolean) => void;
|
||||
defaultState?: boolean;
|
||||
headerText: string;
|
||||
children: React.ReactNode;
|
||||
buttons?: React.ReactNode[];
|
||||
forceOpen?: boolean;
|
||||
}
|
||||
|
||||
export function ExpandableHeader({
|
||||
children,
|
||||
onMoreClick,
|
||||
buttons,
|
||||
moreTooltipText,
|
||||
onDropDownClick,
|
||||
headerText,
|
||||
defaultState = false,
|
||||
forceOpen = false,
|
||||
}: ExpandableHeaderProps) {
|
||||
const [showContent, setShowContent] = useState(defaultState || forceOpen);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "8px"
|
||||
}}>
|
||||
<Text
|
||||
tag="h2"
|
||||
variant="eyebrow"
|
||||
style={{
|
||||
color: "var(--header-primary)",
|
||||
display: "inline"
|
||||
}}
|
||||
>
|
||||
{headerText}
|
||||
</Text>
|
||||
|
||||
<div className={cl("center-flex")}>
|
||||
{
|
||||
buttons ?? null
|
||||
}
|
||||
|
||||
{
|
||||
onMoreClick && // only show more button if callback is provided
|
||||
<Tooltip text={moreTooltipText}>
|
||||
{tooltipProps => (
|
||||
<button
|
||||
{...tooltipProps}
|
||||
className={cl("btn")}
|
||||
onClick={onMoreClick}>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path fill="var(--text-normal)" d="M7 12.001C7 10.8964 6.10457 10.001 5 10.001C3.89543 10.001 3 10.8964 3 12.001C3 13.1055 3.89543 14.001 5 14.001C6.10457 14.001 7 13.1055 7 12.001ZM14 12.001C14 10.8964 13.1046 10.001 12 10.001C10.8954 10.001 10 10.8964 10 12.001C10 13.1055 10.8954 14.001 12 14.001C13.1046 14.001 14 13.1055 14 12.001ZM19 10.001C20.1046 10.001 21 10.8964 21 12.001C21 13.1055 20.1046 14.001 19 14.001C17.8954 14.001 17 13.1055 17 12.001C17 10.8964 17.8954 10.001 19 10.001Z" />
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</Tooltip>
|
||||
}
|
||||
|
||||
|
||||
<Tooltip text={showContent ? "Hide " + headerText : "Show " + headerText}>
|
||||
{tooltipProps => (
|
||||
<button
|
||||
{...tooltipProps}
|
||||
className={cl("btn")}
|
||||
onClick={() => {
|
||||
setShowContent(v => !v);
|
||||
onDropDownClick?.(showContent);
|
||||
}}
|
||||
disabled={forceOpen}
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
transform={showContent ? "scale(1 -1)" : "scale(1 1)"}
|
||||
>
|
||||
<path fill="var(--text-normal)" d="M16.59 8.59003L12 13.17L7.41 8.59003L6 10L12 16L18 10L16.59 8.59003Z" />
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
{showContent && children}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -18,9 +18,8 @@
|
|||
|
||||
import "./iconStyles.css";
|
||||
|
||||
import { getTheme, Theme } from "@utils/discord";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { classes } from "@utils/misc";
|
||||
import { i18n } from "@webpack/common";
|
||||
import type { PropsWithChildren } from "react";
|
||||
|
||||
interface BaseIconProps extends IconProps {
|
||||
|
@ -123,8 +122,8 @@ export function InfoIcon(props: IconProps) {
|
|||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
transform="translate(2 2)"
|
||||
d="M9,7 L11,7 L11,5 L9,5 L9,7 Z M10,18 C5.59,18 2,14.41 2,10 C2,5.59 5.59,2 10,2 C14.41,2 18,5.59 18,10 C18,14.41 14.41,18 10,18 L10,18 Z M10,4.4408921e-16 C4.4771525,-1.77635684e-15 4.4408921e-16,4.4771525 0,10 C-1.33226763e-15,12.6521649 1.0535684,15.195704 2.92893219,17.0710678 C4.80429597,18.9464316 7.3478351,20 10,20 C12.6521649,20 15.195704,18.9464316 17.0710678,17.0710678 C18.9464316,15.195704 20,12.6521649 20,10 C20,7.3478351 18.9464316,4.80429597 17.0710678,2.92893219 C15.195704,1.0535684 12.6521649,2.22044605e-16 10,0 L10,4.4408921e-16 Z M9,15 L11,15 L11,9 L9,9 L9,15 L9,15 Z"
|
||||
fill-rule="evenodd"
|
||||
d="M23 12a11 11 0 1 1-22 0 11 11 0 0 1 22 0Zm-9.5-4.75a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm-.77 3.96a1 1 0 1 0-1.96-.42l-1.04 4.86a2.77 2.77 0 0 0 4.31 2.83l.24-.17a1 1 0 1 0-1.16-1.62l-.24.17a.77.77 0 0 1-1.2-.79l1.05-4.86Z" clip-rule="evenodd"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
|
@ -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"
|
||||
|
@ -212,9 +211,10 @@ export function CogWheel(props: IconProps) {
|
|||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
fill="currentColor"
|
||||
d="M19.738 10H22V14H19.739C19.498 14.931 19.1 15.798 18.565 16.564L20 18L18 20L16.565 18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069 19.498 8.203 19.099 7.436 18.564L6 20L4 18L5.436 16.564C4.901 15.799 4.502 14.932 4.262 14H2V10H4.262C4.502 9.068 4.9 8.202 5.436 7.436L4 6L6 4L7.436 5.436C8.202 4.9 9.068 4.502 10 4.262V2H14V4.261C14.932 4.502 15.797 4.9 16.565 5.435L18 3.999L20 5.999L18.564 7.436C19.099 8.202 19.498 9.069 19.738 10ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z"
|
||||
fill-rule="evenodd"
|
||||
d="M10.56 1.1c-.46.05-.7.53-.64.98.18 1.16-.19 2.2-.98 2.53-.8.33-1.79-.15-2.49-1.1-.27-.36-.78-.52-1.14-.24-.77.59-1.45 1.27-2.04 2.04-.28.36-.12.87.24 1.14.96.7 1.43 1.7 1.1 2.49-.33.8-1.37 1.16-2.53.98-.45-.07-.93.18-.99.64a11.1 11.1 0 0 0 0 2.88c.06.46.54.7.99.64 1.16-.18 2.2.19 2.53.98.33.8-.14 1.79-1.1 2.49-.36.27-.52.78-.24 1.14.59.77 1.27 1.45 2.04 2.04.36.28.87.12 1.14-.24.7-.95 1.7-1.43 2.49-1.1.8.33 1.16 1.37.98 2.53-.07.45.18.93.64.99a11.1 11.1 0 0 0 2.88 0c.46-.06.7-.54.64-.99-.18-1.16.19-2.2.98-2.53.8-.33 1.79.14 2.49 1.1.27.36.78.52 1.14.24.77-.59 1.45-1.27 2.04-2.04.28-.36.12-.87-.24-1.14-.96-.7-1.43-1.7-1.1-2.49.33-.8 1.37-1.16 2.53-.98.45.07.93-.18.99-.64a11.1 11.1 0 0 0 0-2.88c-.06-.46-.54-.7-.99-.64-1.16.18-2.2-.19-2.53-.98-.33-.8.14-1.79 1.1-2.49.36-.27.52-.78.24-1.14a11.07 11.07 0 0 0-2.04-2.04c-.36-.28-.87-.12-1.14.24-.7.96-1.7 1.43-2.49 1.1-.8-.33-1.16-1.37-.98-2.53.07-.45-.18-.93-.64-.99a11.1 11.1 0 0 0-2.88 0ZM16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
|
@ -407,23 +407,30 @@ export function PencilIcon(props: IconProps) {
|
|||
);
|
||||
}
|
||||
|
||||
const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg";
|
||||
const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg";
|
||||
const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg";
|
||||
const GithubIconDark = "/assets/6a853b4c87fce386cbfef4a2efbacb09.svg";
|
||||
|
||||
export function GithubIcon(props: ImageProps) {
|
||||
const src = getTheme() === Theme.Light
|
||||
? GithubIconLight
|
||||
: GithubIconDark;
|
||||
|
||||
return <img {...props} src={src} />;
|
||||
export function GithubIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
viewBox="-3 -3 30 30"
|
||||
>
|
||||
<path
|
||||
fill={props.fill || "currentColor"}
|
||||
d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.438 9.8 8.205 11.385.6.11.82-.26.82-.577v-2.17c-3.338.726-4.042-1.61-4.042-1.61-.546-1.387-1.333-1.757-1.333-1.757-1.09-.745.083-.73.083-.73 1.205.084 1.84 1.237 1.84 1.237 1.07 1.835 2.807 1.305 3.492.998.108-.775.42-1.305.763-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.467-2.38 1.235-3.22-.123-.303-.535-1.523.117-3.176 0 0 1.008-.322 3.3 1.23.957-.266 1.98-.398 3-.403 1.02.005 2.043.137 3 .403 2.29-1.552 3.297-1.23 3.297-1.23.653 1.653.24 2.873.118 3.176.77.84 1.233 1.91 1.233 3.22 0 4.61-2.803 5.625-5.475 5.92.43.37.823 1.102.823 2.222v3.293c0 .32.218.694.825.577C20.565 21.797 24 17.298 24 12c0-6.63-5.37-12-12-12z"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
||||
export function WebsiteIcon(props: ImageProps) {
|
||||
const src = getTheme() === Theme.Light
|
||||
? WebsiteIconLight
|
||||
: WebsiteIconDark;
|
||||
|
||||
return <img {...props} src={src} />;
|
||||
export function WebsiteIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill={props.fill || "currentColor"}
|
||||
d="M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10 10-4.486 10-10S17.514 2 12 2zM4 12c0-.899.156-1.762.431-2.569L6 11l2 2v2l2 2 1 1v1.931C7.061 19.436 4 16.072 4 12zm14.33 4.873C17.677 16.347 16.687 16 16 16v-1a2 2 0 0 0-2-2h-4v-3a2 2 0 0 0 2-2V7h1a2 2 0 0 0 2-2v-.411C17.928 5.778 20 8.65 20 12a7.947 7.947 0 0 1-1.67 4.873z"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,16 +6,19 @@
|
|||
|
||||
import "./LinkIconButton.css";
|
||||
|
||||
import { getTheme, Theme } from "@utils/discord";
|
||||
import { MaskedLink, Tooltip } from "@webpack/common";
|
||||
|
||||
import { GithubIcon, WebsiteIcon } from "..";
|
||||
|
||||
export function GithubLinkIcon() {
|
||||
return <GithubIcon aria-hidden className={"vc-settings-modal-link-icon"} />;
|
||||
const theme = getTheme() === Theme.Light ? "#000000" : "#FFFFFF";
|
||||
return <GithubIcon aria-hidden fill={theme} className={"vc-settings-modal-link-icon"} />;
|
||||
}
|
||||
|
||||
export function WebsiteLinkIcon() {
|
||||
return <WebsiteIcon aria-hidden className={"vc-settings-modal-link-icon"} />;
|
||||
const theme = getTheme() === Theme.Light ? "#000000" : "#FFFFFF";
|
||||
return <WebsiteIcon aria-hidden fill={theme} className={"vc-settings-modal-link-icon"} />;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -10,7 +10,6 @@ export * from "./CodeBlock";
|
|||
export * from "./DonateButton";
|
||||
export { default as ErrorBoundary } from "./ErrorBoundary";
|
||||
export * from "./ErrorCard";
|
||||
export * from "./ExpandableHeader";
|
||||
export * from "./Flex";
|
||||
export * from "./Heart";
|
||||
export * from "./Icons";
|
||||
|
|
|
@ -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, nativeTheme } from "electron";
|
||||
import electron, { app, BrowserWindowConstructorOptions, Menu } from "electron";
|
||||
import { dirname, join } from "path";
|
||||
|
||||
import { initIpc } from "./ipcMain";
|
||||
|
@ -100,19 +100,6 @@ 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,13 +71,16 @@ export async function installExt(id: string) {
|
|||
// React Devtools v4.25
|
||||
// v4.27 is broken in Electron, see https://github.com/facebook/react/issues/25843
|
||||
// Unfortunately, Google does not serve old versions, so this is the only way
|
||||
// This zip file is pinned to long commit hash so it cannot be changed remotely
|
||||
? "https://raw.githubusercontent.com/Vendicated/random-files/f6f550e4c58ac5f2012095a130406c2ab25b984d/fmkadmapgofadopljbjfkapdkoienihi.zip"
|
||||
: `https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D${id}%26uc&prodversion=32`;
|
||||
: `https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D${id}%26uc&prodversion=${process.versions.chrome}`;
|
||||
|
||||
const buf = await get(url, {
|
||||
headers: {
|
||||
"User-Agent": "Vencord (https://github.com/Vendicated/Vencord)"
|
||||
"User-Agent": `Electron ${process.versions.electron} ~ Vencord (https://github.com/Vendicated/Vencord)`
|
||||
}
|
||||
});
|
||||
|
||||
await extract(crxToZip(buf), extDir).catch(console.error);
|
||||
}
|
||||
|
||||
|
|
5
src/plugins/_api/badges/fixDiscordBadgePadding.css
Normal file
5
src/plugins/_api/badges/fixDiscordBadgePadding.css
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* the profile popout badge container(s) */
|
||||
[class*="biteSize_"] [class*="tags_"] [class*="container_"] {
|
||||
/* Discord has padding set to 2px instead of 1px, which causes the 12th badge to wrap to a new line. */
|
||||
padding: 0 1px;
|
||||
}
|
|
@ -16,6 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./fixDiscordBadgePadding.css";
|
||||
|
||||
import { _getBadges, BadgePosition, BadgeUserArgs, ProfileBadge } from "@api/Badges";
|
||||
import DonateButton from "@components/DonateButton";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
|
|
|
@ -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) => "" +
|
||||
|
|
|
@ -23,11 +23,14 @@ export default definePlugin({
|
|||
name: "MessagePopoverAPI",
|
||||
description: "API to add buttons to message popovers.",
|
||||
authors: [Devs.KingFish, Devs.Ven, Devs.Nuckyz],
|
||||
patches: [{
|
||||
find: "Messages.MESSAGE_UTILITIES_A11Y_LABEL",
|
||||
patches: [
|
||||
{
|
||||
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))/,
|
||||
replace: "$&,Vencord.Api.MessagePopover._buildPopoverElements($1,$2)"
|
||||
match: /(?<=:null),(.{0,40}togglePopout:.+?}\))\]}\):null,(?<=\((\i\.\i),{label:.+?:null,(\i&&!\i)\?\(0,\i\.jsxs?\)\(\i\.Fragment.+?message:(\i).+?)/,
|
||||
replace: (_, ReactButton, ButtonComponent, showReactButton, message) => "" +
|
||||
`]}):null,Vencord.Api.MessagePopover._buildPopoverElements(${ButtonComponent},${message}),${showReactButton}?${ReactButton}:null,`
|
||||
}
|
||||
}],
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -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($&)"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,13 +61,13 @@ export default definePlugin({
|
|||
]
|
||||
},
|
||||
{
|
||||
find: ".installedLogHooks)",
|
||||
find: ".BetterDiscord||null!=",
|
||||
replacement: {
|
||||
// if getDebugLogging() returns false, the hooks don't get installed.
|
||||
match: "getDebugLogging(){",
|
||||
replace: "getDebugLogging(){return false;"
|
||||
// Make hasClientMods return false
|
||||
match: /(?=let \i=window;)/,
|
||||
replace: "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;
|
||||
|
||||
try {
|
||||
const names = {
|
||||
top: i18n.Messages.USER_SETTINGS,
|
||||
aboveNitro: i18n.Messages.BILLING_SETTINGS,
|
||||
belowNitro: i18n.Messages.APP_SETTINGS,
|
||||
aboveActivity: i18n.Messages.ACTIVITY_SETTINGS
|
||||
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(),
|
||||
|
|
|
@ -147,9 +147,9 @@ export default definePlugin({
|
|||
settings,
|
||||
|
||||
patches: [{
|
||||
find: ".BEGINNING_DM.format",
|
||||
find: "#{intl::BEGINNING_DM}",
|
||||
replacement: {
|
||||
match: /BEGINNING_DM\.format\(\{.+?\}\),(?=.{0,300}(\i)\.isMultiUserDM)/,
|
||||
match: /#{intl::BEGINNING_DM},{.+?}\),(?=.{0,300}(\i)\.isMultiUserDM)/,
|
||||
replace: "$& $self.renderContributorDmWarningCard({ channel: $1 }),"
|
||||
}
|
||||
}],
|
||||
|
|
|
@ -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: {
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -51,7 +51,7 @@ export default definePlugin({
|
|||
{
|
||||
find: "bitbucket.org",
|
||||
replacement: {
|
||||
match: /function \i\(\i\){(?=.{0,60}\.parse\(\i\))/,
|
||||
match: /function \i\(\i\){(?=.{0,30}pathname:\i)/,
|
||||
replace: "$&return null;"
|
||||
},
|
||||
predicate: () => settings.store.file
|
||||
|
|
|
@ -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,"
|
||||
},
|
||||
},
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { canonicalizeMatch } from "@utils/patches";
|
||||
import { execFile } from "child_process";
|
||||
import { promisify } from "util";
|
||||
|
||||
|
@ -26,7 +27,7 @@ interface RemoteData {
|
|||
let cachedRemoteData: { id: string, data: RemoteData; } | { id: string, failures: number; } | null = null;
|
||||
|
||||
const APPLE_MUSIC_BUNDLE_REGEX = /<script type="module" crossorigin src="([a-zA-Z0-9.\-/]+)"><\/script>/;
|
||||
const APPLE_MUSIC_TOKEN_REGEX = /\w+="([A-Za-z0-9-_]*\.[A-Za-z0-9-_]*\.[A-Za-z0-9-_]*)",\w+="x-apple-jingle-correlation-key"/;
|
||||
const APPLE_MUSIC_TOKEN_REGEX = canonicalizeMatch(/Promise.allSettled\(\i\)\}const \i="([A-Za-z0-9-_]*\.[A-Za-z0-9-_]*\.[A-Za-z0-9-_]*)"/);
|
||||
|
||||
let cachedToken: string | undefined = undefined;
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
@ -122,7 +123,7 @@ export default definePlugin({
|
|||
},
|
||||
// If we are rendering the Better Folders sidebar, we filter out everything but the servers and folders from the GuildsBar Guild List children
|
||||
{
|
||||
match: /lastTargetNode:\i\[\i\.length-1\].+?Fragment.+?\]}\)\]/,
|
||||
match: /lastTargetNode:\i\[\i\.length-1\].+?}\)\](?=}\))/,
|
||||
replace: "$&.filter($self.makeGuildsBarGuildListFilter(!!arguments[0]?.isBetterFolders))"
|
||||
},
|
||||
// If we are rendering the Better Folders sidebar, we filter out everything but the scroller for the guild list from the GuildsBar Tree children
|
||||
|
@ -158,7 +159,7 @@ export default definePlugin({
|
|||
]
|
||||
},
|
||||
{
|
||||
find: ".FOLDER_ITEM_GUILD_ICON_MARGIN);",
|
||||
find: ".expandedFolderBackground,",
|
||||
predicate: () => settings.store.sidebar,
|
||||
replacement: [
|
||||
// We use arguments[0] to access the isBetterFolders variable in this nested folder component (the parent exports all the props so we don't have to patch it)
|
||||
|
@ -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
|
||||
|
@ -184,7 +185,7 @@ export default definePlugin({
|
|||
{
|
||||
// Decide if we should render the expanded folder background if we are rendering the Better Folders sidebar
|
||||
predicate: () => settings.store.showFolderIcon !== FolderIconDisplay.Always,
|
||||
match: /(?<=\.wrapper,children:\[)/,
|
||||
match: /(?<=\.isExpanded\),children:\[)/,
|
||||
replace: "$self.shouldShowFolderIconAndBackground(!!arguments[0]?.isBetterFolders,arguments[0]?.betterFoldersExpandedIds)&&"
|
||||
},
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -275,19 +276,29 @@ export default definePlugin({
|
|||
|
||||
makeGuildsBarGuildListFilter(isBetterFolders: boolean) {
|
||||
return child => {
|
||||
if (isBetterFolders) {
|
||||
return child?.props?.["aria-label"] === i18n.Messages.SERVERS;
|
||||
if (!isBetterFolders) return true;
|
||||
|
||||
try {
|
||||
return child?.props?.["aria-label"] === getIntlMessage("SERVERS");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
},
|
||||
|
||||
makeGuildsBarTreeFilter(isBetterFolders: boolean) {
|
||||
return child => {
|
||||
if (isBetterFolders) {
|
||||
return child?.props?.onScroll != null;
|
||||
}
|
||||
if (!isBetterFolders) return true;
|
||||
|
||||
if (child?.props?.className?.includes("itemsContainer") && child.props.children != null) {
|
||||
// Filter out everything but the scroller for the guild list
|
||||
child.props.children = child.props.children.filter(child => child?.props?.onScroll != null);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -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,"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -75,10 +75,11 @@ export default definePlugin({
|
|||
patches: [{
|
||||
find: "renderConnectionStatus(){",
|
||||
replacement: {
|
||||
match: /(?<=renderConnectionStatus\(\)\{.+\.channel,children:)\i/,
|
||||
match: /(?<=renderConnectionStatus\(\){.+\.channel,children:).+?}\):\i(?=}\))/,
|
||||
replace: "[$&, $self.renderTimer(this.props.channel.id)]"
|
||||
}
|
||||
}],
|
||||
|
||||
renderTimer(channelId: string) {
|
||||
return <ErrorBoundary noop>
|
||||
<this.Timer channelId={channelId} />
|
||||
|
|
|
@ -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",
|
||||
|
@ -110,7 +110,7 @@ const settings = definePluginSettings({
|
|||
|
||||
export default definePlugin({
|
||||
name: "ClientTheme",
|
||||
authors: [Devs.F53, Devs.Nuckyz],
|
||||
authors: [Devs.Nuckyz],
|
||||
description: "Recreation of the old client theme experiment. Add a color to your Discord client theme",
|
||||
settings,
|
||||
|
||||
|
|
|
@ -66,6 +66,20 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "https://github.com/highlightjs/highlight.js/issues/2277",
|
||||
replacement: {
|
||||
match: /(?<=&&\()console.log\(`Deprecated.+?`\),/,
|
||||
replace: ""
|
||||
}
|
||||
},
|
||||
{
|
||||
find: 'The "interpolate" function is deprecated in v10 (use "to" instead)',
|
||||
replacement: {
|
||||
match: /,console.warn\(\i\+'The "interpolate" function is deprecated in v10 \(use "to" instead\)'\)/,
|
||||
replace: ""
|
||||
}
|
||||
},
|
||||
{
|
||||
find: 'console.warn("Window state not initialized"',
|
||||
replacement: {
|
||||
|
@ -119,7 +133,7 @@ export default definePlugin({
|
|||
{
|
||||
find: "Slow dispatch on",
|
||||
replacement: {
|
||||
match: /\i\.totalTime>100&&\i\.verbose\("Slow dispatch on ".+?\)\);/,
|
||||
match: /\i\.totalTime>\i&&\i\.verbose\("Slow dispatch on ".+?\)\);/,
|
||||
replace: ""
|
||||
}
|
||||
},
|
||||
|
@ -140,5 +154,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,10 +95,13 @@ export const useUsersDecorationsStore = proxyLazy(() => zustandCreate((set: any,
|
|||
} as UsersDecorationsState)));
|
||||
|
||||
export function useUserDecorAvatarDecoration(user?: User): AvatarDecoration | null | undefined {
|
||||
try {
|
||||
const [decorAvatarDecoration, setDecorAvatarDecoration] = useState<string | null>(user ? useUsersDecorationsStore.getState().getAsset(user.id) ?? null : null);
|
||||
|
||||
useEffect(() => {
|
||||
const destructor = useUsersDecorationsStore.subscribe(
|
||||
const destructor = (() => {
|
||||
try {
|
||||
return useUsersDecorationsStore.subscribe(
|
||||
state => {
|
||||
if (!user) return;
|
||||
const newDecorAvatarDecoration = state.getAsset(user.id);
|
||||
|
@ -106,13 +109,25 @@ export function useUserDecorAvatarDecoration(user?: User): AvatarDecoration | nu
|
|||
if (decorAvatarDecoration !== newDecorAvatarDecoration) setDecorAvatarDecoration(newDecorAvatarDecoration);
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
return () => { };
|
||||
}
|
||||
})();
|
||||
|
||||
try {
|
||||
if (user) {
|
||||
const { fetch: fetchUserDecorAvatarDecoration } = useUsersDecorationsStore.getState();
|
||||
fetchUserDecorAvatarDecoration(user.id);
|
||||
}
|
||||
} catch { }
|
||||
|
||||
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")}>
|
||||
|
|
|
@ -16,18 +16,16 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { migratePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
migratePluginSettings("DisableCallIdle", "DisableDMCallIdle");
|
||||
export default definePlugin({
|
||||
name: "DisableCallIdle",
|
||||
description: "Disables automatically getting kicked from a DM voice call after 3 minutes and being moved to an AFK voice channel.",
|
||||
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;"
|
||||
|
|
|
@ -310,7 +310,8 @@ function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable<Om
|
|||
}
|
||||
|
||||
function isGifUrl(url: string) {
|
||||
return new URL(url).pathname.endsWith(".gif");
|
||||
const u = new URL(url);
|
||||
return u.pathname.endsWith(".gif") || u.searchParams.get("animated") === "true";
|
||||
}
|
||||
|
||||
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
|
||||
|
|
|
@ -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, 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";
|
||||
|
@ -207,8 +207,8 @@ function makeBypassPatches(): Omit<Patch, "plugin"> {
|
|||
return {
|
||||
find: "canUseCustomStickersEverywhere:",
|
||||
replacement: mapping.map(({ func, predicate }) => ({
|
||||
match: new RegExp(String.raw`(?<=${func}:function\(\i(?:,\i)?\){)`),
|
||||
replace: "return true;",
|
||||
match: new RegExp(String.raw`(?<=${func}:)\i`),
|
||||
replace: "() => true",
|
||||
predicate
|
||||
}))
|
||||
};
|
||||
|
@ -285,7 +285,7 @@ export default definePlugin({
|
|||
},
|
||||
// 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,
|
||||
|
@ -297,8 +297,8 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
// Overwrite incoming connection settings proto with our local settings
|
||||
match: /CONNECTION_OPEN:function\((\i)\){/,
|
||||
replace: (m, props) => `${m}$self.handleProtoChange(${props}.userSettingsProto,${props}.user);`
|
||||
match: /function (\i)\((\i)\){(?=.*CONNECTION_OPEN:\1)/,
|
||||
replace: (m, funcName, props) => `${m}$self.handleProtoChange(${props}.userSettingsProto,${props}.user);`
|
||||
},
|
||||
{
|
||||
// Overwrite non local proto changes with our local settings
|
||||
|
@ -356,7 +356,7 @@ export default definePlugin({
|
|||
]
|
||||
},
|
||||
{
|
||||
find: ".Messages.STICKER_POPOUT_UNJOINED_PRIVATE_GUILD_DESCRIPTION.format",
|
||||
find: "#{intl::STICKER_POPOUT_UNJOINED_PRIVATE_GUILD_DESCRIPTION}",
|
||||
predicate: () => settings.store.transformStickers,
|
||||
replacement: [
|
||||
{
|
||||
|
@ -381,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
|
||||
|
@ -920,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);
|
||||
|
||||
|
@ -953,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})"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ export default definePlugin({
|
|||
{
|
||||
// https://regex101.com/r/x2mobQ/1
|
||||
// searchEmojis(...,maxCount: stuff) ... endEmojis = emojis.slice(0, maxCount - gifResults.length)
|
||||
match: /,maxCount:(\i)(.{1,500}\i)=(\i)\.slice\(0,(\i-\i\.length)\)/,
|
||||
match: /,maxCount:(\i)(.{1,500}\i)=(\i)\.slice\(0,(Math\.max\(\i,\i(?:-\i\.length){2}\))\)/,
|
||||
// ,maxCount:Infinity ... endEmojis = (emojis.sliceTo = n, emojis)
|
||||
replace: ",maxCount:Infinity$2=($3.sliceTo = $4, $3)"
|
||||
}
|
||||
|
|
|
@ -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}),`
|
||||
}
|
||||
},
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { FluxDispatcher, React, useRef, useState } from "@webpack/common";
|
||||
import { FluxDispatcher, useLayoutEffect, useRef, useState } from "@webpack/common";
|
||||
|
||||
import { ELEMENT_ID } from "../constants";
|
||||
import { settings } from "../index";
|
||||
|
@ -55,7 +55,7 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
|
|||
const imageRef = useRef<HTMLImageElement | null>(null);
|
||||
|
||||
// since we accessing document im gonna use useLayoutEffect
|
||||
React.useLayoutEffect(() => {
|
||||
useLayoutEffect(() => {
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Shift") {
|
||||
isShiftDown.current = true;
|
||||
|
@ -135,12 +135,14 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
|
|||
|
||||
setReady(true);
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
document.addEventListener("keyup", onKeyUp);
|
||||
document.addEventListener("mousemove", updateMousePosition);
|
||||
document.addEventListener("mousedown", onMouseDown);
|
||||
document.addEventListener("mouseup", onMouseUp);
|
||||
document.addEventListener("wheel", onWheel);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", onKeyDown);
|
||||
document.removeEventListener("keyup", onKeyUp);
|
||||
|
@ -148,13 +150,15 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
|
|||
document.removeEventListener("mousedown", onMouseDown);
|
||||
document.removeEventListener("mouseup", onMouseUp);
|
||||
document.removeEventListener("wheel", onWheel);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(() => () => {
|
||||
if (settings.store.saveZoomValues) {
|
||||
settings.store.zoom = zoom.current;
|
||||
settings.store.size = size.current;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
});
|
||||
|
||||
if (!ready) return null;
|
||||
|
||||
|
|
|
@ -179,6 +179,11 @@ export default definePlugin({
|
|||
{
|
||||
match: /componentWillUnmount\(\){/,
|
||||
replace: "$&$self.unMountMagnifier();"
|
||||
},
|
||||
|
||||
{
|
||||
match: /componentDidUpdate\(\i\){/,
|
||||
replace: "$&$self.updateMagnifier(this);"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -215,6 +220,11 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
|
||||
updateMagnifier(instance) {
|
||||
this.unMountMagnifier();
|
||||
this.renderMagnifier(instance);
|
||||
},
|
||||
|
||||
unMountMagnifier() {
|
||||
this.root?.unmount();
|
||||
this.currentMagnifierElement = null;
|
||||
|
|
|
@ -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) {
|
||||
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
|
||||
|
|
|
@ -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: /MESSAGE_DELETE:function\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?},/,
|
||||
match: /function (?=.+?MESSAGE_DELETE:(\i))\1\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?}(?=function)/,
|
||||
replace:
|
||||
"MESSAGE_DELETE:function($1){" +
|
||||
" var cache = $2getOrCreate($1.channelId);" +
|
||||
" cache = $self.handleDelete(cache, $1, false);" +
|
||||
" $2commit(cache);" +
|
||||
"},"
|
||||
"function $1($2){" +
|
||||
" var cache = $3getOrCreate($2.channelId);" +
|
||||
" cache = $self.handleDelete(cache, $2, false);" +
|
||||
" $3commit(cache);" +
|
||||
"}"
|
||||
},
|
||||
{
|
||||
// Add deleted=true to all target messages in the MESSAGE_DELETE_BULK event
|
||||
match: /MESSAGE_DELETE_BULK:function\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?},/,
|
||||
match: /function (?=.+?MESSAGE_DELETE_BULK:(\i))\1\((\i)\){let.+?((?:\i\.){2})getOrCreate.+?}(?=function)/,
|
||||
replace:
|
||||
"MESSAGE_DELETE_BULK:function($1){" +
|
||||
" var cache = $2getOrCreate($1.channelId);" +
|
||||
" cache = $self.handleDelete(cache, $1, true);" +
|
||||
" $2commit(cache);" +
|
||||
"},"
|
||||
"function $1($2){" +
|
||||
" var cache = $3getOrCreate($2.channelId);" +
|
||||
" cache = $self.handleDelete(cache, $2, true);" +
|
||||
" $3commit(cache);" +
|
||||
"}"
|
||||
},
|
||||
{
|
||||
// Add current cached content + new edit time to cached message's editHistory
|
||||
match: /(MESSAGE_UPDATE:function\((\i)\).+?)\.update\((\i)/,
|
||||
match: /(function (\i)\((\i)\).+?)\.update\((\i)(?=.*MESSAGE_UPDATE:\2)/,
|
||||
replace: "$1" +
|
||||
".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)]) :" +
|
||||
".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)]) :" +
|
||||
" m" +
|
||||
")" +
|
||||
".update($3"
|
||||
".update($4"
|
||||
},
|
||||
{
|
||||
// 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:function\((\i)\).+?},/,
|
||||
replace: "MESSAGE_DELETE:function($1){},"
|
||||
match: /MESSAGE_DELETE:\i,/,
|
||||
replace: "MESSAGE_DELETE:()=>{},"
|
||||
},
|
||||
{
|
||||
match: /MESSAGE_DELETE_BULK:function\((\i)\).+?},/,
|
||||
replace: "MESSAGE_DELETE_BULK:function($1){},"
|
||||
match: /MESSAGE_DELETE_BULK:\i,/,
|
||||
replace: "MESSAGE_DELETE_BULK:()=>{},"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -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)=\{\}\)\)\[(\i)\.BOT/,
|
||||
replace: "($1=$self.getTagTypes()))[$2.BOT"
|
||||
match: /(?=(\i)\[\i\.BOT)/,
|
||||
replace: "$self.genTagTypes($1);"
|
||||
}
|
||||
},
|
||||
{
|
||||
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"
|
||||
|
@ -279,8 +280,7 @@ export default definePlugin({
|
|||
.filter(Boolean);
|
||||
},
|
||||
|
||||
getTagTypes() {
|
||||
const obj = {};
|
||||
genTagTypes(obj) {
|
||||
let i = 100;
|
||||
tags.forEach(({ name }) => {
|
||||
obj[name] = ++i;
|
||||
|
@ -290,27 +290,30 @@ export default definePlugin({
|
|||
obj[`${name}-OP`] = ++i;
|
||||
obj[i] = `${name}-OP`;
|
||||
});
|
||||
return obj;
|
||||
},
|
||||
|
||||
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;
|
||||
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 strings.APP_TAG;
|
||||
if (variant === "BOT" && tagName !== "WEBHOOK" && this.settings.store.dontShowForBots) return strings.APP_TAG;
|
||||
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}`;
|
||||
return `${getIntlMessage("BOT_TAG_FORUM_ORIGINAL_POSTER")} • ${tagText}`;
|
||||
case "BOT":
|
||||
return `${strings.APP_TAG} • ${tagText}`;
|
||||
return `${getIntlMessage("APP_TAG")} • ${tagText}`;
|
||||
default:
|
||||
return tagText;
|
||||
}
|
||||
} catch {
|
||||
return originalText;
|
||||
}
|
||||
},
|
||||
|
||||
getTag({
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { isNonNullish } from "@utils/guards";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
|
||||
import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, useMemo, UserStore } from "@webpack/common";
|
||||
|
@ -87,7 +88,7 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
match: /\i\.useEffect.{0,100}(\i)\[0\]\.section/,
|
||||
replace: "$self.pushSection($1, arguments[0].user);$&"
|
||||
replace: "$self.pushSection($1,arguments[0].user);$&"
|
||||
},
|
||||
{
|
||||
match: /\(0,\i\.jsx\)\(\i,\{items:\i,section:(\i)/,
|
||||
|
@ -97,14 +98,32 @@ export default definePlugin({
|
|||
},
|
||||
{
|
||||
find: 'section:"MUTUAL_FRIENDS"',
|
||||
replacement: {
|
||||
match: /\.openUserProfileModal.+?\)}\)}\)(?<=(\(0,\i\.jsxs?\)\(\i\.\i,{className:(\i)\.divider}\)).+?)/,
|
||||
replace: "$&,$self.renderDMPageList({user: arguments[0].user, Divider: $1, listStyle: $2.list})"
|
||||
replacement: [
|
||||
{
|
||||
match: /\i\|\|\i(?=\?\(0,\i\.jsxs?\)\(\i\.\i\.Overlay,)/,
|
||||
replace: "$&||$self.getMutualGroupDms(arguments[0].user.id).length>0"
|
||||
},
|
||||
{
|
||||
match: /\.openUserProfileModal.+?\)}\)}\)(?<=,(\i)&&(\i)&&(\(0,\i\.jsxs?\)\(\i\.\i,{className:(\i)\.divider}\)).+?)/,
|
||||
replace: (m, hasMutualGuilds, hasMutualFriends, Divider, classes) => "" +
|
||||
`${m},$self.renderDMPageList({user:arguments[0].user,hasDivider:${hasMutualGuilds}||${hasMutualFriends},Divider:${Divider},listStyle:${classes}.list})`
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
getMutualGroupDms(userId: string) {
|
||||
try {
|
||||
return getMutualGroupDms(userId);
|
||||
} catch (e) {
|
||||
new Logger("MutualGroupDMs").error("Failed to get mutual group dms:", e);
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
|
||||
pushSection(sections: any[], user: User) {
|
||||
try {
|
||||
if (isBotOrSelf(user) || sections[IS_PATCHED]) return;
|
||||
|
||||
sections[IS_PATCHED] = true;
|
||||
|
@ -112,11 +131,13 @@ export default definePlugin({
|
|||
section: "MUTUAL_GDMS",
|
||||
text: getMutualGDMCountText(user)
|
||||
});
|
||||
} catch (e) {
|
||||
new Logger("MutualGroupDMs").error("Failed to push mutual group dms section:", e);
|
||||
}
|
||||
},
|
||||
|
||||
renderMutualGDMs: ErrorBoundary.wrap(({ user, onClose }: { user: User, onClose: () => void; }) => {
|
||||
const mutualGDms = useMemo(() => getMutualGroupDms(user.id), [user.id]);
|
||||
|
||||
const entries = renderClickableGDMs(mutualGDms, onClose);
|
||||
|
||||
return (
|
||||
|
@ -138,14 +159,13 @@ export default definePlugin({
|
|||
);
|
||||
}),
|
||||
|
||||
renderDMPageList: ErrorBoundary.wrap(({ user, Divider, listStyle }: { user: User, Divider: JSX.Element, listStyle: string; }) => {
|
||||
renderDMPageList: ErrorBoundary.wrap(({ user, hasDivider, Divider, listStyle }: { user: User, hasDivider: boolean, Divider: JSX.Element, listStyle: string; }) => {
|
||||
const mutualGDms = getMutualGroupDms(user.id);
|
||||
if (mutualGDms.length === 0) return null;
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{Divider}
|
||||
{hasDivider && Divider}
|
||||
<ExpandableList
|
||||
listClassName={listStyle}
|
||||
header={"Mutual Groups"}
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
findGroupChildrenByChildId,
|
||||
NavContextMenuPatchCallback
|
||||
} from "@api/ContextMenu";
|
||||
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { CogWheel } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
@ -115,8 +115,6 @@ function applyDefaultSettings(guildId: string | null) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
migratePluginSettings("NewGuildSettings", "MuteNewGuild");
|
||||
export default definePlugin({
|
||||
name: "NewGuildSettings",
|
||||
description: "Automatically mute new servers and change various other settings upon joining",
|
||||
|
|
|
@ -18,17 +18,18 @@
|
|||
|
||||
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 {
|
||||
collapsedReason: {
|
||||
message: string;
|
||||
};
|
||||
// Internal intl message for BLOCKED_MESSAGE_COUNT
|
||||
collapsedReason: () => any;
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
|
@ -37,7 +38,7 @@ export default definePlugin({
|
|||
authors: [Devs.rushii, Devs.Samu],
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.BLOCKED_MESSAGES_HIDE",
|
||||
find: "#{intl::BLOCKED_MESSAGES_HIDE}",
|
||||
replacement: [
|
||||
{
|
||||
match: /let\{[^}]*collapsedReason[^}]*\}/,
|
||||
|
@ -53,8 +54,8 @@ export default definePlugin({
|
|||
predicate: () => Settings.plugins.NoBlockedMessages.ignoreBlockedMessages === true,
|
||||
replacement: [
|
||||
{
|
||||
match: /(?<=MESSAGE_CREATE:function\((\i)\){)/,
|
||||
replace: (_, props) => `if($self.isBlocked(${props}.message))return;`
|
||||
match: /(?<=function (\i)\((\i)\){)(?=.*MESSAGE_CREATE:\1)/,
|
||||
replace: (_, _funcName, props) => `if($self.isBlocked(${props}.message))return;`
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
@ -77,6 +78,11 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
shouldHide(props: MessageDeleteProps) {
|
||||
return !props?.collapsedReason?.message.includes("deleted");
|
||||
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();return",
|
||||
predicate: () => settings.store.hideMessageRequestsCount,
|
||||
replacement: {
|
||||
match: /(?<=getSpamChannelsCount\(\),\i=)\i\.getMessageRequestsCount\(\)/,
|
||||
match: /(?<=getSpamChannelsCount\(\);return )\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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,20 +16,27 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { getUserSettingLazy } from "@api/UserSettings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
const DisableStreamPreviews = getUserSettingLazy<boolean>("voiceAndVideo", "disableStreamPreviews")!;
|
||||
|
||||
// @TODO: Delete this plugin in the future
|
||||
export default definePlugin({
|
||||
name: "NoScreensharePreview",
|
||||
description: "Disables screenshare previews from being sent.",
|
||||
authors: [Devs.Nuckyz],
|
||||
patches: [
|
||||
{
|
||||
find: '"ApplicationStreamPreviewUploadManager"',
|
||||
replacement: {
|
||||
match: /await \i\.\i\.(makeChunkedRequest\(|post\(\{url:)\i\.\i\.STREAM_PREVIEW.+?\}\)/g,
|
||||
replace: "0"
|
||||
|
||||
start() {
|
||||
if (!DisableStreamPreviews.getSetting()) {
|
||||
DisableStreamPreviews.updateSetting(true);
|
||||
}
|
||||
},
|
||||
|
||||
stop() {
|
||||
if (DisableStreamPreviews.getSetting()) {
|
||||
DisableStreamPreviews.updateSetting(false);
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
5
src/plugins/noUnblockToJump/README.md
Normal file
5
src/plugins/noUnblockToJump/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# No Unblock To Jump
|
||||
|
||||
Removes the popup preventing you to jump to a message from a blocked/ignored user (eg: in search results)
|
||||
|
||||
![A modal popup telling you to unblock a user to jump their message](https://github.com/user-attachments/assets/0e4b859d-f3b3-4101-9a83-829afb473d1e)
|
|
@ -26,25 +26,46 @@ export default definePlugin({
|
|||
authors: [Devs.dzshn],
|
||||
patches: [
|
||||
{
|
||||
// Clicking on search results to jump
|
||||
find: '.id,"Search Results"',
|
||||
replacement: {
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}UNBLOCK_TO_JUMP_TITLE)/,
|
||||
replacement: [
|
||||
{
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}#{intl::UNBLOCK_TO_JUMP_TITLE})/,
|
||||
replace: "if(false)$1"
|
||||
}
|
||||
},
|
||||
{
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}#{intl::UNIGNORE_TO_JUMP_TITLE})/,
|
||||
replace: "if(false)$1"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
// Jump buttton in top right corner of messages
|
||||
find: "renderJumpButton()",
|
||||
replacement: {
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}UNBLOCK_TO_JUMP_TITLE)/,
|
||||
replacement: [
|
||||
{
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}#{intl::UNBLOCK_TO_JUMP_TITLE})/,
|
||||
replace: "if(false)$1"
|
||||
}
|
||||
},
|
||||
{
|
||||
match: /if\(.{1,10}\)(.{1,10}\.show\({.{1,50}#{intl::UNIGNORE_TO_JUMP_TITLE})/,
|
||||
replace: "if(false)$1"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
// Clicking on replied messages to jump
|
||||
find: "flash:!0,returnMessageId",
|
||||
replacement: {
|
||||
match: /.\?(.{1,10}\.show\({.{1,50}UNBLOCK_TO_JUMP_TITLE)/,
|
||||
replacement: [
|
||||
{
|
||||
match: /.\?(.{1,10}\.show\({.{1,50}#{intl::UNBLOCK_TO_JUMP_TITLE})/,
|
||||
replace: "false?$1"
|
||||
}
|
||||
},
|
||||
{
|
||||
match: /.\?(.{1,10}\.show\({.{1,50}#{intl::UNIGNORE_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))",
|
||||
|
|
|
@ -57,7 +57,7 @@ const UrlReplacementRules: Record<string, URLReplacementRule> = {
|
|||
description: "Open Tidal links in the Tidal app",
|
||||
},
|
||||
itunes: {
|
||||
match: /^https:\/\/music\.apple\.com\/([a-z]{2}\/)?(album|artist|playlist|song|curator)\/([^/?#]+)\/?([^/?#]+)?(?:\?.*)?(?:#.*)?$/,
|
||||
match: /^https:\/\/(?:geo\.)?music\.apple\.com\/([a-z]{2}\/)?(album|artist|playlist|song|curator)\/([^/?#]+)\/?([^/?#]+)?(?:\?.*)?(?:#.*)?$/,
|
||||
replace: (_, lang, type, name, id) => id ? `itunes://music.apple.com/us/${type}/${name}/${id}` : `itunes://music.apple.com/us/${type}/${name}`,
|
||||
description: "Open Apple Music links in the iTunes app"
|
||||
},
|
||||
|
@ -87,7 +87,7 @@ 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;"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType, ReporterTestable } from "@utils/types";
|
||||
import { FluxDispatcher } from "@webpack/common";
|
||||
|
@ -41,7 +41,6 @@ const settings = definePluginSettings({
|
|||
},
|
||||
});
|
||||
|
||||
migratePluginSettings("PartyMode", "Party mode 🎉");
|
||||
export default definePlugin({
|
||||
name: "PartyMode",
|
||||
description: "Allows you to use party mode cause the party never ends ✨",
|
||||
|
|
|
@ -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,15 +19,15 @@
|
|||
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, i18n, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, useMemo, UserStore, useState, useStateFromStores } from "@webpack/common";
|
||||
import { UnicodeEmoji } from "@webpack/types";
|
||||
import type { Guild, Role, User } from "discord-types/general";
|
||||
|
||||
import { settings } from "..";
|
||||
import { cl, getPermissionDescription, getPermissionString } from "../utils";
|
||||
import { cl, getGuildPermissionSpecMap } from "../utils";
|
||||
import { PermissionAllowedIcon, PermissionDefaultIcon, PermissionDeniedIcon } from "./icons";
|
||||
|
||||
export const enum PermissionType {
|
||||
|
@ -56,7 +56,7 @@ function getRoleIconSrc(role: Role) {
|
|||
}
|
||||
|
||||
function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, header }: { permissions: Array<RoleOrUserPermission>; guild: Guild; modalProps: ModalProps; header: string; }) {
|
||||
permissions.sort((a, b) => a.type - b.type);
|
||||
const guildPermissionSpecMap = useMemo(() => getGuildPermissionSpecMap(guild), [guild.id]);
|
||||
|
||||
useStateFromStores(
|
||||
[GuildMemberStore],
|
||||
|
@ -65,6 +65,10 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea
|
|||
(old, current) => old.length === current.length
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
permissions.sort((a, b) => a.type - b.type);
|
||||
}, [permissions]);
|
||||
|
||||
useEffect(() => {
|
||||
const usersToRequest = permissions
|
||||
.filter(p => p.type === PermissionType.User && !GuildMemberStore.isMember(guild.id, p.id!))
|
||||
|
@ -173,7 +177,7 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea
|
|||
</ScrollerThin>
|
||||
<div className={cl("modal-divider")} />
|
||||
<ScrollerThin className={cl("modal-perms")} orientation="auto">
|
||||
{Object.entries(PermissionsBits).map(([permissionName, bit]) => (
|
||||
{Object.values(PermissionsBits).map(bit => (
|
||||
<div className={cl("modal-perms-item")}>
|
||||
<div className={cl("modal-perms-item-icon")}>
|
||||
{(() => {
|
||||
|
@ -192,9 +196,14 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea
|
|||
return PermissionDefaultIcon();
|
||||
})()}
|
||||
</div>
|
||||
<Text variant="text-md/normal">{getPermissionString(permissionName)}</Text>
|
||||
<Text variant="text-md/normal">{guildPermissionSpecMap[String(bit)].title}</Text>
|
||||
|
||||
<Tooltip text={getPermissionDescription(permissionName) || "No Description"}>
|
||||
<Tooltip text={
|
||||
(() => {
|
||||
const { description } = guildPermissionSpecMap[String(bit)];
|
||||
return typeof description === "function" ? i18n.intl.format(description, {}) : description;
|
||||
})()
|
||||
}>
|
||||
{props => <InfoIcon {...props} />}
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
@ -216,7 +225,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 +234,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 +266,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);
|
||||
}}
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
*/
|
||||
|
||||
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 "..";
|
||||
import { cl, getPermissionString, getSortedRoles, sortUserRoles } from "../utils";
|
||||
import { cl, getGuildPermissionSpecMap, getSortedRoles, sortUserRoles } from "../utils";
|
||||
import openRolesAndUsersPermissionsModal, { PermissionType, type RoleOrUserPermission } from "./RolesAndUsersPermissions";
|
||||
|
||||
interface UserPermission {
|
||||
|
@ -86,9 +86,11 @@ function GrantedByTooltip({ roleName, roleColor }: GrantedByTooltipProps) {
|
|||
);
|
||||
}
|
||||
|
||||
function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { guild: Guild; guildMember: GuildMember; forceOpen?: boolean; }) {
|
||||
function UserPermissionsComponent({ guild, guildMember, closePopout }: { guild: Guild; guildMember: GuildMember; closePopout: () => void; }) {
|
||||
const { permissionsSortOrder } = settings.use(["permissionsSortOrder"]);
|
||||
|
||||
const guildPermissionSpecMap = useMemo(() => getGuildPermissionSpecMap(guild), [guild.id]);
|
||||
|
||||
const [rolePermissions, userPermissions] = useMemo(() => {
|
||||
const userPermissions: UserPermissions = [];
|
||||
|
||||
|
@ -105,7 +107,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",
|
||||
|
@ -116,11 +118,11 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
|
|||
|
||||
sortUserRoles(userRoles);
|
||||
|
||||
for (const [permission, bit] of Object.entries(PermissionsBits)) {
|
||||
for (const bit of Object.values(PermissionsBits)) {
|
||||
for (const { permissions, colorString, position, name } of userRoles) {
|
||||
if ((permissions & bit) === bit) {
|
||||
userPermissions.push({
|
||||
permission: getPermissionString(permission),
|
||||
permission: guildPermissionSpecMap[String(bit)].title,
|
||||
roleName: name,
|
||||
roleColor: colorString || "var(--primary-300)",
|
||||
rolePosition: position
|
||||
|
@ -136,26 +138,15 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
|
|||
return [rolePermissions, userPermissions];
|
||||
}, [permissionsSortOrder]);
|
||||
|
||||
return (
|
||||
<ExpandableHeader
|
||||
forceOpen={forceOpen}
|
||||
headerText="Permissions"
|
||||
moreTooltipText="Role Details"
|
||||
onMoreClick={() =>
|
||||
openRolesAndUsersPermissionsModal(
|
||||
rolePermissions,
|
||||
guild,
|
||||
guildMember.nick || UserStore.getUser(guildMember.userId).username
|
||||
)
|
||||
}
|
||||
onDropDownClick={state => settings.store.defaultPermissionsDropdownState = !state}
|
||||
defaultState={settings.store.defaultPermissionsDropdownState}
|
||||
buttons={[
|
||||
return <div>
|
||||
<div className={cl("user-header-container")}>
|
||||
<Text variant="eyebrow">Permissions</Text>
|
||||
<div className={cl("user-header-btns")}>
|
||||
<Tooltip text={`Sorting by ${permissionsSortOrder === PermissionsSortOrder.HighestRole ? "Highest Role" : "Lowest Role"}`}>
|
||||
{tooltipProps => (
|
||||
<div
|
||||
{...tooltipProps}
|
||||
className={cl("user-sortorder-btn")}
|
||||
className={cl("user-header-btn")}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => {
|
||||
|
@ -163,8 +154,8 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
|
|||
}}
|
||||
>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 96 960 960"
|
||||
transform={permissionsSortOrder === PermissionsSortOrder.HighestRole ? "scale(1 1)" : "scale(1 -1)"}
|
||||
>
|
||||
|
@ -173,7 +164,30 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
|
|||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
]}>
|
||||
<Tooltip text="Role Details">
|
||||
{tooltipProps => (
|
||||
<div
|
||||
{...tooltipProps}
|
||||
className={cl("user-header-btn")}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => {
|
||||
closePopout();
|
||||
openRolesAndUsersPermissionsModal(rolePermissions, guild, guildMember.nick || UserStore.getUser(guildMember.userId).username);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path fill="var(--text-normal)" d="M7 12.001C7 10.8964 6.10457 10.001 5 10.001C3.89543 10.001 3 10.8964 3 12.001C3 13.1055 3.89543 14.001 5 14.001C6.10457 14.001 7 13.1055 7 12.001ZM14 12.001C14 10.8964 13.1046 10.001 12 10.001C10.8954 10.001 10 10.8964 10 12.001C10 13.1055 10.8954 14.001 12 14.001C13.1046 14.001 14 13.1055 14 12.001ZM19 10.001C20.1046 10.001 21 10.8964 21 12.001C21 13.1055 20.1046 14.001 19 14.001C17.8954 14.001 17 13.1055 17 12.001C17 10.8964 17.8954 10.001 19 10.001Z" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
{userPermissions.length > 0 && (
|
||||
<div className={classes(RoleRootClasses.root)}>
|
||||
{userPermissions.map(({ permission, roleColor, roleName }) => (
|
||||
|
@ -189,8 +203,7 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
|
|||
))}
|
||||
</div>
|
||||
)}
|
||||
</ExpandableHeader>
|
||||
);
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default ErrorBoundary.wrap(UserPermissionsComponent, { noop: true });
|
||||
|
|
|
@ -56,11 +56,6 @@ export const settings = definePluginSettings({
|
|||
{ label: "Lowest Role", value: PermissionsSortOrder.LowestRole }
|
||||
]
|
||||
},
|
||||
defaultPermissionsDropdownState: {
|
||||
description: "Whether the permissions dropdown on user popouts should be open by default",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
|
||||
|
@ -170,7 +165,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: ".VIEW_ALL_ROLES,",
|
||||
find: "#{intl::VIEW_ALL_ROLES}",
|
||||
replacement: {
|
||||
match: /\.expandButton,.+?null,/,
|
||||
replace: "$&$self.ViewPermissionsButton(arguments[0]),"
|
||||
|
@ -182,9 +177,9 @@ export default definePlugin({
|
|||
<Popout
|
||||
position="bottom"
|
||||
align="center"
|
||||
renderPopout={() => (
|
||||
renderPopout={({ closePopout }) => (
|
||||
<Dialog className={PopoutClasses.container} style={{ width: "500px" }}>
|
||||
<UserPermissions guild={guild} guildMember={guildMember} forceOpen />
|
||||
<UserPermissions guild={guild} guildMember={guildMember} closePopout={closePopout} />
|
||||
</Dialog>
|
||||
)}
|
||||
>
|
||||
|
|
|
@ -1,12 +1,22 @@
|
|||
/* User Permissions Component */
|
||||
|
||||
.vc-permviewer-user-sortorder-btn {
|
||||
.vc-permviewer-user-header-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.vc-permviewer-user-header-btns {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.vc-permviewer-user-header-btn {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
/* RolesAndUsersPermissions Component */
|
||||
|
|
|
@ -17,56 +17,17 @@
|
|||
*/
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { wordsToTitle } from "@utils/text";
|
||||
import { GuildStore, i18n, Parser } from "@webpack/common";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { GuildStore } from "@webpack/common";
|
||||
import { Guild, GuildMember, Role } from "discord-types/general";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { PermissionsSortOrder, settings } from ".";
|
||||
import { PermissionType } from "./components/RolesAndUsersPermissions";
|
||||
|
||||
export const { getGuildPermissionSpecMap } = findByPropsLazy("getGuildPermissionSpecMap");
|
||||
|
||||
export const cl = classNameFactory("vc-permviewer-");
|
||||
|
||||
function formatPermissionWithoutMatchingString(permission: string) {
|
||||
return wordsToTitle(permission.toLowerCase().split("_"));
|
||||
}
|
||||
|
||||
// because discord is unable to be consistent with their names
|
||||
const PermissionKeyMap = {
|
||||
MANAGE_GUILD: "MANAGE_SERVER",
|
||||
MANAGE_GUILD_EXPRESSIONS: "MANAGE_EXPRESSIONS",
|
||||
CREATE_GUILD_EXPRESSIONS: "CREATE_EXPRESSIONS",
|
||||
MODERATE_MEMBERS: "MODERATE_MEMBER", // HELLOOOO ??????
|
||||
STREAM: "VIDEO",
|
||||
SEND_VOICE_MESSAGES: "ROLE_PERMISSIONS_SEND_VOICE_MESSAGE",
|
||||
} as const;
|
||||
|
||||
export function getPermissionString(permission: string) {
|
||||
permission = PermissionKeyMap[permission] || permission;
|
||||
|
||||
return i18n.Messages[permission] ||
|
||||
// shouldn't get here but just in case
|
||||
formatPermissionWithoutMatchingString(permission);
|
||||
}
|
||||
|
||||
export function getPermissionDescription(permission: string): ReactNode {
|
||||
// DISCORD PLEEEEEEEEAAAAASE IM BEGGING YOU :(
|
||||
if (permission === "USE_APPLICATION_COMMANDS")
|
||||
permission = "USE_APPLICATION_COMMANDS_GUILD";
|
||||
else if (permission === "SEND_VOICE_MESSAGES")
|
||||
permission = "SEND_VOICE_MESSAGE_GUILD";
|
||||
else if (permission !== "STREAM")
|
||||
permission = PermissionKeyMap[permission] || permission;
|
||||
|
||||
const msg = i18n.Messages[`ROLE_PERMISSIONS_${permission}_DESCRIPTION`] as any;
|
||||
if (msg?.hasMarkdown)
|
||||
return Parser.parse(msg.message);
|
||||
|
||||
if (typeof msg === "string") return msg;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
export function getSortedRoles({ id }: Guild, member: GuildMember) {
|
||||
const roles = GuildStore.getRoles(id);
|
||||
|
||||
|
|
|
@ -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"/);
|
||||
|
|
|
@ -71,7 +71,7 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
// Filter out pinned channels from the private channel list
|
||||
match: /(?<=\i,{channels:\i,)privateChannelIds:(\i)/,
|
||||
match: /(?<=channels:\i,)privateChannelIds:(\i)(?=,listRef:)/,
|
||||
replace: "privateChannelIds:$1.filter(c=>!$self.isPinned(c))"
|
||||
},
|
||||
{
|
||||
|
@ -96,8 +96,8 @@ export default definePlugin({
|
|||
|
||||
// Fix Row Height
|
||||
{
|
||||
match: /(?<="getRowHeight",.{1,100}return 1===)\i/,
|
||||
replace: "($&-$self.categoryLen())"
|
||||
match: /(\.startsWith\("section-divider"\).+?return 1===)(\i)/,
|
||||
replace: "$1($2-$self.categoryLen())"
|
||||
},
|
||||
{
|
||||
match: /"getRowHeight",\((\i),(\i)\)=>{/,
|
||||
|
@ -124,7 +124,7 @@ export default definePlugin({
|
|||
{
|
||||
find: ".FRIENDS},\"friends\"",
|
||||
replacement: {
|
||||
match: /(?<=\i=\i=>{).{1,100}premiumTabSelected.{1,800}showDMHeader:.+?,/,
|
||||
match: /(?<=\i=\i=>{).{1,100}premiumTabSelected.{0,950}showDMHeader:.+?,/,
|
||||
replace: "let forceUpdate = Vencord.Util.useForceUpdater();$&_forceUpdate:forceUpdate,"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -20,7 +20,7 @@ import { definePluginSettings, Settings } from "@api/Settings";
|
|||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { ChannelStore, FluxDispatcher as Dispatcher, MessageStore, PermissionsBits, PermissionStore, SelectedChannelStore, UserStore } from "@webpack/common";
|
||||
import { ChannelStore, ComponentDispatch, FluxDispatcher as Dispatcher, MessageStore, PermissionsBits, PermissionStore, SelectedChannelStore, UserStore } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
const Kangaroo = findByPropsLazy("jumpToMessage");
|
||||
|
@ -60,24 +60,24 @@ export default definePlugin({
|
|||
settings,
|
||||
|
||||
start() {
|
||||
Dispatcher.subscribe("DELETE_PENDING_REPLY", onDeletePendingReply);
|
||||
Dispatcher.subscribe("MESSAGE_END_EDIT", onEndEdit);
|
||||
Dispatcher.subscribe("MESSAGE_START_EDIT", onStartEdit);
|
||||
Dispatcher.subscribe("CREATE_PENDING_REPLY", onCreatePendingReply);
|
||||
document.addEventListener("keydown", onKeydown);
|
||||
},
|
||||
|
||||
stop() {
|
||||
Dispatcher.unsubscribe("DELETE_PENDING_REPLY", onDeletePendingReply);
|
||||
Dispatcher.unsubscribe("MESSAGE_END_EDIT", onEndEdit);
|
||||
Dispatcher.unsubscribe("MESSAGE_START_EDIT", onStartEdit);
|
||||
Dispatcher.unsubscribe("CREATE_PENDING_REPLY", onCreatePendingReply);
|
||||
document.removeEventListener("keydown", onKeydown);
|
||||
},
|
||||
});
|
||||
|
||||
const onDeletePendingReply = () => replyIdx = -1;
|
||||
const onEndEdit = () => editIdx = -1;
|
||||
flux: {
|
||||
DELETE_PENDING_REPLY() {
|
||||
replyIdx = -1;
|
||||
},
|
||||
MESSAGE_END_EDIT() {
|
||||
editIdx = -1;
|
||||
},
|
||||
MESSAGE_START_EDIT: onStartEdit,
|
||||
CREATE_PENDING_REPLY: onCreatePendingReply
|
||||
}
|
||||
});
|
||||
|
||||
function calculateIdx(messages: Message[], id: string) {
|
||||
const idx = messages.findIndex(m => m.id === id);
|
||||
|
@ -109,6 +109,8 @@ function onKeydown(e: KeyboardEvent) {
|
|||
if (!isUp && e.key !== "ArrowDown") return;
|
||||
if (!isCtrl(e) || isAltOrMeta(e)) return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
if (e.shiftKey)
|
||||
nextEdit(isUp);
|
||||
else
|
||||
|
@ -194,9 +196,10 @@ function nextReply(isUp: boolean) {
|
|||
channel,
|
||||
message,
|
||||
shouldMention: shouldMention(message),
|
||||
showMentionToggle: channel.guild_id !== null && message.author.id !== meId,
|
||||
showMentionToggle: channel.isPrivate() && message.author.id !== meId,
|
||||
_isQuickReply: true
|
||||
});
|
||||
ComponentDispatch.dispatchToLastSubscribed("TEXTAREA_FOCUS");
|
||||
jumpIfOffScreen(channel.id, message.id);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),`
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue