Compare commits

...

37 Commits

Author SHA1 Message Date
Lewis Crichton
64c7581286 feat(permissionfreewill): onboarding deletion 2023-10-03 17:46:17 +01:00
Vendicated
30b2e88e77 Bump to v1.5.4 2023-10-03 02:29:57 +02:00
TheKodeToad
1f38a8eeab Fix WhoReacted (#1769) 2023-10-03 02:26:38 +02:00
Vendicated
6db9721c06 ReviewDB: fix usericons appearing over modals 2023-10-03 02:17:28 +02:00
Dea
9891791fa7 feat(plugin): onePingPerDM (#1757)
Co-authored-by: V <vendicated@riseup.net>
2023-10-03 01:53:14 +02:00
Lewis Crichton
8dd5eeead2 feat(plugin): PermissionFreeWill (#1763)
Co-authored-by: V <vendicated@riseup.net>
2023-10-03 01:26:57 +02:00
whqwert
abf8667a5d fix(plugin): Party mode 🎉 2023-10-02 23:17:51 +02:00
Vendicated
e33ac900bc Merge remote-tracking branch 'origin/main' into dev 2023-10-02 23:10:07 +02:00
V
8a026060c7 Update blank.yml 2023-09-29 19:01:55 +02:00
V
c8b77bb187 Update bug_report.yml 2023-09-29 19:00:50 +02:00
AutumnVN
88b06191b9 fix modal image + reviewdb bot tag (#1761)
* fix modal image

* fix reviewdb bot tag
2023-09-29 00:46:33 +02:00
Vendicated
62277770a8 bump to v1.5.3 2023-09-28 02:42:55 +02:00
V
4facc3cad7 webContextMenus: support pasting images 2023-09-27 04:13:40 +02:00
TheKodeToad
837d1fc083 web: fix themes tab (#1756) 2023-09-26 21:47:12 +02:00
V
608a67c9ae fix quick/searchReply & MessageClickactions not working in dms 2023-09-26 03:54:59 +02:00
AutumnVN
f32d25b641 viewRaw, viewIcons, permissionsViewer: fix some edge cases (#1745)
Co-authored-by: V <vendicated@riseup.net>
2023-09-26 01:48:09 +02:00
V
4c7a2ba340 Merge branch 'main' into dev 2023-09-26 01:45:38 +02:00
V
da7f0cfff6 PluginModal: Fix cancel button being white on white in light theme 2023-09-26 01:38:46 +02:00
V
ae6584da7c add os-accent-color variable (following BetterDiscord) 2023-09-25 18:53:10 +02:00
V
c6b1b9463c improve webpack find error messages 2023-09-25 18:27:18 +02:00
V
376aaf39ce fix SearchReply filter 2023-09-25 18:07:43 +02:00
V
5454a41243 update issue templates 2023-09-25 04:27:16 +02:00
Hugo C
044f64e446 Improve permission checks on several plugins (#1746)
Co-authored-by: V <vendicated@riseup.net>
2023-09-24 16:42:53 +02:00
V
0b7fca864a plugin READMEs: migrate from imgur to github assets 2023-09-24 16:17:33 +02:00
V
30ac256070 migrate all plugins to folders 2023-09-24 16:02:18 +02:00
Sam
d0e2a32471 VcNarrator: Ignore multiple underscores (#1748)
Co-authored-by: V <vendicated@riseup.net>
2023-09-24 15:55:23 +02:00
V
ec026ca34c Update bug_report.yml 2023-09-24 15:45:22 +02:00
V
4baaa9bd91 Delete .github/ISSUE_TEMPLATE/feature_request.yml 2023-09-24 15:44:02 +02:00
V
d9933c5793 settingsSync: correctly use platform agnostic relaunch 2023-09-24 01:16:50 +02:00
V
2735037a67 [skip ci] bump to v1.5.2 2023-09-24 01:12:00 +02:00
Dziurwa
83bfe28fa4 FriendInvites: Add picking uses (1 or 5) (#1727)
Co-authored-by: V <vendicated@riseup.net>
2023-09-23 03:50:14 +02:00
V
08c5d23636 add max attempts to lazys 2023-09-23 03:25:19 +02:00
V
ac0f834155 Fix Plugin Settings on canary 2023-09-23 03:15:07 +02:00
V
fa16e1b56f fix updater 2023-09-22 15:58:29 +02:00
V
cfca393f2b ci(generatePluginList): add filePath 2023-09-22 04:48:54 +02:00
Nuckyz
eacc673bcc Fix BetterRoleDot making reporter angry 2023-09-21 23:28:40 -03:00
Nuckyz
dba6c4cea6 Fix broken FakeNitro patch (again) 2023-09-21 22:41:25 -03:00
134 changed files with 507 additions and 288 deletions

30
.github/ISSUE_TEMPLATE/blank.yml vendored Normal file
View File

@ -0,0 +1,30 @@
name: Blank Issue
description: Create a blank issue. ALWAYS FIRST USE OUR SUPPORT CHANNEL! ONLY USE THIS FORM IF YOU ARE A CONTRIBUTOR OR WERE TOLD TO DO SO IN THE SUPPORT CHANNEL.
body:
- type: markdown
attributes:
value: |
# READ THIS BEFORE OPENING AN ISSUE
This form is ONLY FOR DEVELOPERS. YOUR ISSUE WILL BE CLOSED AND YOU WILL POSSIBLY BE BLOCKED FROM THE REPOSITORY IF YOU IGNORE THIS.
DO NOT USE THIS FORM, unless
- you are a vencord contributor
- you were given explicit permission to use this form by a moderator in our support server
- you are filing a security related report
- type: textarea
id: content
attributes:
label: Content
validations:
required: true
- type: checkboxes
id: agreement-check
attributes:
label: Request Agreement
options:
- label: I have read the requirements for opening an issue above
required: true

View File

@ -1,9 +1,21 @@
name: Bug/Crash Report
description: Create a bug or crash report for Vencord
description: Create a bug or crash report for Vencord. ALWAYS FIRST USE OUR SUPPORT CHANNEL! ONLY USE THIS FORM IF YOU ARE A CONTRIBUTOR OR WERE TOLD TO DO SO IN THE SUPPORT CHANNEL.
labels: [bug]
title: "[Bug] <title>"
body:
- type: markdown
attributes:
value: |
# READ THIS BEFORE OPENING AN ISSUE
This form is ONLY FOR DEVELOPERS. YOUR ISSUE WILL BE CLOSED AND YOU WILL POSSIBLY BE BLOCKED FROM THE REPOSITORY IF YOU IGNORE THIS.
DO NOT USE THIS FORM, unless
- you are a vencord contributor
- you were given explicit permission to use this form by a moderator in our support server
- you are filing a security related report
- type: input
id: discord
attributes:
@ -64,3 +76,5 @@ body:
options:
- label: I am using Discord Stable or tried on Stable and this bug happens there as well
required: true
- label: I have read the requirements for opening an issue above
required: true

View File

@ -1,4 +1,4 @@
blank_issues_enabled: true
blank_issues_enabled: false
contact_links:
- name: Vencord Support Server
url: https://discord.gg/D9uwnFnqmd

View File

@ -1,32 +0,0 @@
name: Feature Request
description: Create a feature request for Vencord. To request new plugins, please use the Discussions tab
labels: [enhancement]
title: "[Feature Request] <title>"
body:
- type: input
id: discord
attributes:
label: Discord Account
description: Who on Discord is making this request? Not required but encouraged for easier follow-up
placeholder: username#0000
validations:
required: false
- type: textarea
id: feature-basic-description
attributes:
label: What is it that you'd like to see?
description: Describe the feature you want added as detailed as possible
placeholder: I think ... would be a cool feature to add. This would be awesome, thanks!
validations:
required: true
- type: checkboxes
id: agreement-check
attributes:
label: Request Agreement
description: DO NOT USE THIS TEMPLATE FOR PLUGIN REQUESTS!!! For plugin requests, **use discussions**
options:
- label: This is not a plugin request
required: true

View File

@ -48,7 +48,8 @@ window.VencordNative = {
getThemesList: () => DataStore.entries(themeStore).then(entries =>
entries.map(([name, css]) => getThemeInfo(css, name.toString()))
),
getThemeData: (fileName: string) => DataStore.get(fileName, themeStore)
getThemeData: (fileName: string) => DataStore.get(fileName, themeStore),
getSystemValues: async () => ({}),
},
native: {

View File

@ -1,7 +1,7 @@
{
"name": "vencord",
"private": "true",
"version": "1.5.1",
"version": "1.5.4",
"description": "The cutest Discord client mod",
"homepage": "https://github.com/Vendicated/Vencord#readme",
"bugs": {

View File

@ -25,6 +25,8 @@ const defines = {
IS_STANDALONE: isStandalone,
IS_DEV: JSON.stringify(watch),
IS_UPDATER_DISABLED: updaterDisabled,
IS_WEB: false,
IS_EXTENSION: false,
VERSION: JSON.stringify(VERSION),
BUILD_TIMESTAMP,
};
@ -77,8 +79,6 @@ await Promise.all([
],
define: {
...defines,
IS_WEB: false,
IS_EXTENSION: false,
IS_DISCORD_DESKTOP: true,
IS_VESKTOP: false
}
@ -124,8 +124,6 @@ await Promise.all([
],
define: {
...defines,
IS_WEB: false,
IS_EXTENSION: false,
IS_DISCORD_DESKTOP: false,
IS_VESKTOP: true
}

View File

@ -18,7 +18,8 @@
import { Dirent, readdirSync, readFileSync, writeFileSync } from "fs";
import { access, readFile } from "fs/promises";
import { join } from "path";
import { join, sep } from "path";
import { normalize as posixNormalize, sep as posixSep } from "path/posix";
import { BigIntLiteral, createSourceFile, Identifier, isArrayLiteralExpression, isCallExpression, isExportAssignment, isIdentifier, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, isStringLiteral, isVariableStatement, NamedDeclaration, NodeArray, ObjectLiteralExpression, ScriptTarget, StringLiteral, SyntaxKind } from "typescript";
import { getPluginTarget } from "./utils.mjs";
@ -39,6 +40,7 @@ interface PluginData {
required: boolean;
enabledByDefault: boolean;
target: "discordDesktop" | "vencordDesktop" | "web" | "dev";
filePath: string;
}
const devs = {} as Record<string, Dev>;
@ -165,6 +167,12 @@ async function parseFile(fileName: string) {
data.target = target as any;
}
data.filePath = posixNormalize(fileName)
.split(sep)
.join(posixSep)
.replace(/\/index\.([jt]sx?)$/, "")
.replace(/^src\/plugins\//, "");
let readme = "";
try {
readme = readFileSync(join(fileName, "..", "README.md"), "utf-8");

View File

@ -23,7 +23,8 @@ export default {
deleteTheme: (fileName: string) => invoke<void>(IpcEvents.DELETE_THEME, fileName),
getThemesDir: () => invoke<string>(IpcEvents.GET_THEMES_DIR),
getThemesList: () => invoke<Array<UserThemeHeader>>(IpcEvents.GET_THEMES_LIST),
getThemeData: (fileName: string) => invoke<string | undefined>(IpcEvents.GET_THEME_DATA, fileName)
getThemeData: (fileName: string) => invoke<string | undefined>(IpcEvents.GET_THEME_DATA, fileName),
getSystemValues: () => invoke<Record<string, string>>(IpcEvents.GET_THEME_SYSTEM_VALUES),
},
updater: {

View File

@ -28,8 +28,8 @@ interface BaseIconProps extends IconProps {
interface IconProps extends SVGProps<SVGSVGElement> {
className?: string;
height?: number;
width?: number;
height?: string | number;
width?: string | number;
}
function Icon({ height = 24, width = 24, className, children, viewBox, ...svgProps }: PropsWithChildren<BaseIconProps>) {
@ -97,7 +97,7 @@ export function OpenExternalIcon(props: IconProps) {
>
<polygon
fill="currentColor"
fill-rule="nonzero"
fillRule="nonzero"
points="13 20 11 20 11 8 5.5 13.5 4.08 12.08 12 4.16 19.92 12.08 18.5 13.5 13 8"
/>
</Icon>
@ -121,9 +121,13 @@ export function InfoIcon(props: IconProps) {
<Icon
{...props}
className={classes(props.className, "vc-info-icon")}
viewBox="0 0 12 12"
viewBox="0 0 24 24"
>
<path fill="currentColor" d="M6 1C3.243 1 1 3.244 1 6c0 2.758 2.243 5 5 5s5-2.242 5-5c0-2.756-2.243-5-5-5zm0 2.376a.625.625 0 110 1.25.625.625 0 010-1.25zM7.5 8.5h-3v-1h1V6H5V5h1a.5.5 0 01.5.5v2h1v1z" />
<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"
/>
</Icon>
);
}
@ -139,8 +143,8 @@ export function OwnerCrownIcon(props: IconProps) {
>
<path
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M13.6572 5.42868C13.8879 5.29002 14.1806 5.30402 14.3973 5.46468C14.6133 5.62602 14.7119 5.90068 14.6473 6.16202L13.3139 11.4954C13.2393 11.7927 12.9726 12.0007 12.6666 12.0007H3.33325C3.02725 12.0007 2.76058 11.792 2.68592 11.4954L1.35258 6.16202C1.28792 5.90068 1.38658 5.62602 1.60258 5.46468C1.81992 5.30468 2.11192 5.29068 2.34325 5.42868L5.13192 7.10202L7.44592 3.63068C7.46173 3.60697 7.48377 3.5913 7.50588 3.57559C7.5192 3.56612 7.53255 3.55663 7.54458 3.54535L6.90258 2.90268C6.77325 2.77335 6.77325 2.56068 6.90258 2.43135L7.76458 1.56935C7.89392 1.44002 8.10658 1.44002 8.23592 1.56935L9.09792 2.43135C9.22725 2.56068 9.22725 2.77335 9.09792 2.90268L8.45592 3.54535C8.46794 3.55686 8.48154 3.56651 8.49516 3.57618C8.51703 3.5917 8.53897 3.60727 8.55458 3.63068L10.8686 7.10202L13.6572 5.42868ZM2.66667 12.6673H13.3333V14.0007H2.66667V12.6673Z"
/>
</Icon>
@ -159,8 +163,6 @@ export function ScreenshareIcon(props: IconProps) {
>
<path
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
d="M2 4.5C2 3.397 2.897 2.5 4 2.5H20C21.103 2.5 22 3.397 22 4.5V15.5C22 16.604 21.103 17.5 20 17.5H13V19.5H17V21.5H7V19.5H11V17.5H4C2.897 17.5 2 16.604 2 15.5V4.5ZM13.2 14.3375V11.6C9.864 11.6 7.668 12.6625 6 15C6.672 11.6625 8.532 8.3375 13.2 7.6625V5L18 9.6625L13.2 14.3375Z"
/>
</Icon>
@ -198,8 +200,58 @@ export function Microphone(props: IconProps) {
className={classes(props.className, "vc-microphone")}
viewBox="0 0 24 24"
>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.99 11C14.99 12.66 13.66 14 12 14C10.34 14 9 12.66 9 11V5C9 3.34 10.34 2 12 2C13.66 2 15 3.34 15 5L14.99 11ZM12 16.1C14.76 16.1 17.3 14 17.3 11H19C19 14.42 16.28 17.24 13 17.72V21H11V17.72C7.72 17.23 5 14.41 5 11H6.7C6.7 14 9.24 16.1 12 16.1ZM12 4C11.2 4 11 4.66667 11 5V11C11 11.3333 11.2 12 12 12C12.8 12 13 11.3333 13 11V5C13 4.66667 12.8 4 12 4Z" fill="currentColor" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.99 11C14.99 12.66 13.66 14 12 14C10.34 14 9 12.66 9 11V5C9 3.34 10.34 2 12 2C13.66 2 15 3.34 15 5L14.99 11ZM12 16.1C14.76 16.1 17.3 14 17.3 11H19C19 14.42 16.28 17.24 13 17.72V22H11V17.72C7.72 17.23 5 14.41 5 11H6.7C6.7 14 9.24 16.1 12 16.1Z" fill="currentColor" />
<path fillRule="evenodd" clipRule="evenodd" d="M14.99 11C14.99 12.66 13.66 14 12 14C10.34 14 9 12.66 9 11V5C9 3.34 10.34 2 12 2C13.66 2 15 3.34 15 5L14.99 11ZM12 16.1C14.76 16.1 17.3 14 17.3 11H19C19 14.42 16.28 17.24 13 17.72V21H11V17.72C7.72 17.23 5 14.41 5 11H6.7C6.7 14 9.24 16.1 12 16.1ZM12 4C11.2 4 11 4.66667 11 5V11C11 11.3333 11.2 12 12 12C12.8 12 13 11.3333 13 11V5C13 4.66667 12.8 4 12 4Z" fill="currentColor" />
<path fillRule="evenodd" clipRule="evenodd" d="M14.99 11C14.99 12.66 13.66 14 12 14C10.34 14 9 12.66 9 11V5C9 3.34 10.34 2 12 2C13.66 2 15 3.34 15 5L14.99 11ZM12 16.1C14.76 16.1 17.3 14 17.3 11H19C19 14.42 16.28 17.24 13 17.72V22H11V17.72C7.72 17.23 5 14.41 5 11H6.7C6.7 14 9.24 16.1 12 16.1Z" fill="currentColor" />
</Icon >
);
}
export function CogWheel(props: IconProps) {
return (
<Icon
{...props}
className={classes(props.className, "vc-cog-wheel")}
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"
/>
</Icon>
);
}
export function ReplyIcon(props: IconProps) {
return (
<Icon
{...props}
className={classes(props.className, "vc-reply-icon")}
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M10 8.26667V4L3 11.4667L10 18.9333V14.56C15 14.56 18.5 16.2667 21 20C20 14.6667 17 9.33333 10 8.26667Z"
/>
</Icon>
);
}
export function DeleteIcon(props: IconProps) {
return (
<Icon
{...props}
className={classes(props.className, "vc-delete-icon")}
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M15 3.999V2H9V3.999H3V5.999H21V3.999H15Z"
/>
<path
fill="currentColor"
d="M5 6.99902V18.999C5 20.101 5.897 20.999 7 20.999H17C18.103 20.999 19 20.101 19 18.999V6.99902H5ZM11 17H9V11H11V17ZM15 17H13V11H15V17Z"
/>
</Icon>
);
}

View File

@ -238,7 +238,7 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
<Button
onClick={onClose}
size={Button.Sizes.SMALL}
color={Button.Colors.WHITE}
color={Button.Colors.PRIMARY}
look={Button.Looks.LINK}
>
Cancel

View File

@ -22,6 +22,7 @@ import * as DataStore from "@api/DataStore";
import { showNotice } from "@api/Notices";
import { Settings, useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { CogWheel, InfoIcon } from "@components/Icons";
import PluginModal from "@components/PluginSettings/PluginModal";
import { AddonCard } from "@components/VencordSettings/AddonCard";
import { SettingsTab } from "@components/VencordSettings/shared";
@ -30,9 +31,9 @@ import { Logger } from "@utils/Logger";
import { Margins } from "@utils/margins";
import { classes, isObjectEmpty } from "@utils/misc";
import { openModalLazy } from "@utils/modal";
import { LazyComponent, useAwaiter } from "@utils/react";
import { useAwaiter } from "@utils/react";
import { Plugin } from "@utils/types";
import { findByCode, findByPropsLazy } from "@webpack";
import { findByPropsLazy } from "@webpack";
import { Alerts, Button, Card, Forms, Parser, React, Select, Text, TextInput, Toasts, Tooltip } from "@webpack/common";
import Plugins from "~plugins";
@ -46,8 +47,6 @@ const logger = new Logger("PluginSettings", "#a6d189");
const InputStyles = findByPropsLazy("inputDefault", "inputWrapper");
const ButtonClasses = findByPropsLazy("button", "disabled", "enabled");
const CogWheel = LazyComponent(() => findByCode("18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069"));
const InfoIcon = LazyComponent(() => findByCode("4.4408921e-16 C4.4771525,-1.77635684e-15 4.4408921e-16"));
function showErrorToast(message: string) {
Toasts.show({
@ -163,7 +162,7 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on
<button role="switch" onClick={() => openModal()} className={classes(ButtonClasses.button, cl("info-button"))}>
{plugin.options && !isObjectEmpty(plugin.options)
? <CogWheel />
: <InfoIcon width="24" height="24" />}
: <InfoIcon />}
</button>
}
/>

View File

@ -20,6 +20,7 @@ import { useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { ErrorCard } from "@components/ErrorCard";
import { Flex } from "@components/Flex";
import { DeleteIcon } from "@components/Icons";
import { Link } from "@components/Link";
import { IsFirefox } from "@utils/constants";
import { Margins } from "@utils/margins";
@ -42,7 +43,6 @@ type FileInput = ComponentType<{
}>;
const InviteActions = findByPropsLazy("resolveInvite");
const TrashIcon = findByCodeLazy("M5 6.99902V18.999C5 20.101 5.897 20.999");
const FileInput: FileInput = findByCodeLazy("activateUploadDialogue=");
const TextAreaProps = findLazy(m => typeof m.textarea === "string");
@ -114,7 +114,7 @@ function ThemeCard({ theme, enabled, onChange, onDelete }: ThemeCardProps) {
infoButton={
IS_WEB && (
<div style={{ cursor: "pointer", color: "var(--status-danger" }} onClick={onDelete}>
<TrashIcon />
<DeleteIcon />
</div>
)
}

View File

@ -22,7 +22,7 @@ import "./ipcPlugins";
import { debounce } from "@utils/debounce";
import { IpcEvents } from "@utils/IpcEvents";
import { Queue } from "@utils/Queue";
import { BrowserWindow, ipcMain, shell } from "electron";
import { BrowserWindow, ipcMain, shell, systemPreferences } from "electron";
import { mkdirSync, readFileSync, watch } from "fs";
import { open, readdir, readFile, writeFile } from "fs/promises";
import { join, normalize } from "path";
@ -112,6 +112,10 @@ ipcMain.handle(IpcEvents.SET_QUICK_CSS, (_, css) =>
ipcMain.handle(IpcEvents.GET_THEMES_DIR, () => THEMES_DIR);
ipcMain.handle(IpcEvents.GET_THEMES_LIST, () => listThemes());
ipcMain.handle(IpcEvents.GET_THEME_DATA, (_, fileName) => getThemeData(fileName));
ipcMain.handle(IpcEvents.GET_THEME_SYSTEM_VALUES, () => ({
// win & mac only
"os-accent-color": `#${systemPreferences.getAccentColor?.() || ""}`
}));
ipcMain.handle(IpcEvents.GET_SETTINGS_DIR, () => SETTINGS_DIR);
ipcMain.on(IpcEvents.GET_SETTINGS, e => e.returnValue = readSettings());

View File

@ -47,7 +47,7 @@ export default definePlugin({
{
find: ".ADD_ROLE_A11Y_LABEL",
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout,
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout && !Settings.plugins.BetterRoleDot.bothStyles,
replacement: {
match: /"dot"===\i/,
replace: "true"
@ -55,7 +55,7 @@ export default definePlugin({
},
{
find: ".roleVerifiedIcon",
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout,
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout && !Settings.plugins.BetterRoleDot.bothStyles,
replacement: {
match: /"dot"===\i/,
replace: "true"

View File

@ -24,11 +24,9 @@ import { Margins } from "@utils/margins";
import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
import definePlugin from "@utils/types";
import { findByCodeLazy, findStoreLazy } from "@webpack";
import { EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
import { EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
import { Promisable } from "type-fest";
const MANAGE_EMOJIS_AND_STICKERS = 1n << 30n;
const StickersStore = findStoreLazy("StickersStore");
const uploadEmoji = findByCodeLazy('"EMOJI_UPLOAD_START"', "GUILD_EMOJIS(");
@ -120,7 +118,7 @@ function getGuildCandidates(data: Data) {
return Object.values(GuildStore.getGuilds()).filter(g => {
const canCreate = g.ownerId === meId ||
BigInt(PermissionStore.getGuildPermissions({ id: g.id }) & MANAGE_EMOJIS_AND_STICKERS) === MANAGE_EMOJIS_AND_STICKERS;
(PermissionStore.getGuildPermissions({ id: g.id }) & PermissionsBits.CREATE_GUILD_EXPRESSIONS) === PermissionsBits.CREATE_GUILD_EXPRESSIONS;
if (!canCreate) return false;
if (data.t === "Sticker") return true;

View File

@ -327,8 +327,8 @@ export default definePlugin({
find: ".Messages.EMOJI_POPOUT_UNJOINED_DISCOVERABLE_GUILD_DESCRIPTION",
predicate: () => settings.store.transformEmojis,
replacement: {
match: /(?<=\.Messages\.EMOJI_POPOUT_ADDED_PACK_DESCRIPTION.+?return )(.{0,1200}\.Messages\.EMOJI_POPOUT_UNJOINED_DISCOVERABLE_GUILD_DESCRIPTION.+?)(}\({)/,
replace: (_, reactNode, rest) => `$self.addFakeNotice(${FakeNoticeType.Emoji},${reactNode},!!arguments[0]?.fakeNitroNode?.fake)${rest}fakeNitroNode:arguments[0]?.fakeNitroNode,`
match: /(?<=\.Messages\.EMOJI_POPOUT_ADDED_PACK_DESCRIPTION.+?return ).{0,1200}\.Messages\.EMOJI_POPOUT_UNJOINED_DISCOVERABLE_GUILD_DESCRIPTION.+?(?=}\()/,
replace: reactNode => `$self.addFakeNotice(${FakeNoticeType.Emoji},${reactNode},!!arguments[0]?.fakeNitroNode?.fake)`
}
}
],

View File

@ -2,5 +2,5 @@
Puts your favorite emoji first in the emoji autocomplete.
![FavEmojis](https://i.imgur.com/mEFCoZG.png)
![Example](https://i.imgur.com/wY3Tc43.png)
![a screenshot of the favourite emojis section](https://github.com/Vendicated/Vencord/assets/45497981/419c8c16-1afc-46e0-9cc2-20b9c3489711)
![a comparison of the emoji picker before and after enabling this plugin](https://github.com/Vendicated/Vencord/assets/45497981/4f57626d-cfc6-4155-a47c-2eac191231bb)

View File

@ -2,4 +2,4 @@
Adds a search bar to favorite gifs.
![Screenshot](https://i.imgur.com/Bcgb7PD.png)
![Screenshot](https://github.com/Vendicated/Vencord/assets/45497981/19552adc-d921-4153-976e-e9361dc8fdaf)

View File

@ -1,6 +1,6 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
* 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
@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { ApplicationCommandInputType, sendBotMessage } from "@api/Commands";
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack";
@ -35,30 +35,47 @@ export default definePlugin({
name: "create friend invite",
description: "Generates a friend invite link.",
inputType: ApplicationCommandInputType.BOT,
execute: async (_, ctx) => {
if (!UserStore.getCurrentUser().phone)
options: [{
name: "Uses",
description: "How many uses?",
choices: [
{ label: "1", name: "1", value: "1" },
{ label: "5", name: "5", value: "5" }
],
required: false,
type: ApplicationCommandOptionType.INTEGER
}],
execute: async (args, ctx) => {
const uses = findOption<number>(args, "Uses", 5);
if (uses === 1 && !UserStore.getCurrentUser().phone)
return sendBotMessage(ctx.channel.id, {
content: "You need to have a phone number connected to your account to create a friend invite!"
content: "You need to have a phone number connected to your account to create a friend invite with 1 use!"
});
const random = uuid.v4();
const invite = await RestAPI.post({
url: "/friend-finder/find-friends",
body: {
modified_contacts: {
[random]: [1, "", ""]
},
phone_contact_methods_count: 1
}
}).then(res =>
FriendInvites.createFriendInvite({
code: res.body.invite_suggestions[0][3],
let invite: any;
if (uses === 1) {
const random = uuid.v4();
const { body: { invite_suggestions } } = await RestAPI.post({
url: "/friend-finder/find-friends",
body: {
modified_contacts: {
[random]: [1, "", ""]
},
phone_contact_methods_count: 1
}
});
invite = await FriendInvites.createFriendInvite({
code: invite_suggestions[0][3],
recipient_phone_number_or_email: random,
contact_visibility: 1,
filter_visibilities: [],
filtered_invite_suggestions_index: 1
})
);
});
} else {
invite = await FriendInvites.createFriendInvite();
}
sendBotMessage(ctx.channel.id, {
content: `
@ -67,7 +84,7 @@ export default definePlugin({
Max uses: \`${invite.max_uses}\`
`.trim().replace(/\s+/g, " ")
});
},
}
},
{
name: "view friend invites",
@ -95,7 +112,7 @@ export default definePlugin({
execute: async (_, ctx) => {
await FriendInvites.revokeFriendInvites();
return void sendBotMessage(ctx.channel.id, {
sendBotMessage(ctx.channel.id, {
content: "All friend invites have been revoked."
});
},

View File

@ -2,5 +2,5 @@
Lets you zoom in to images and gifs. Use scroll wheel to zoom in and shift + scroll wheel to increase lens radius / size
![Example](https://i.imgur.com/VJdo4aq.png)
![ContextMenu](https://i.imgur.com/0oaRM2s.png)
![the plugin in action](https://github.com/Vendicated/Vencord/assets/45497981/408cd77d-c5f4-40bc-8de2-f977a31b3e5f)
![the context menu options offered by the plugin](https://github.com/Vendicated/Vencord/assets/45497981/3bede636-f1ce-493f-af46-788b920cb81c)

View File

@ -0,0 +1,5 @@
# MessageClickActions
Allows you to double click to edit/reply to a message or delete it if you hold the backspace key
![](https://github.com/Vendicated/Vencord/assets/55940580/6885aca2-4021-4910-b636-bb40f877a816)

View File

@ -21,18 +21,17 @@ import { definePluginSettings, Settings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { FluxDispatcher, PermissionStore, UserStore } from "@webpack/common";
import { FluxDispatcher, PermissionsBits, PermissionStore, UserStore } from "@webpack/common";
let isDeletePressed = false;
const keydown = (e: KeyboardEvent) => e.key === "Backspace" && (isDeletePressed = true);
const keyup = (e: KeyboardEvent) => e.key === "Backspace" && (isDeletePressed = false);
const MANAGE_CHANNELS = 1n << 4n;
const settings = definePluginSettings({
enableDeleteOnClick: {
type: OptionType.BOOLEAN,
description: "Enable delete on click",
description: "Enable delete on click while holding backspace",
default: true
},
enableDoubleClickToEdit: {
@ -72,6 +71,7 @@ export default definePlugin({
if (!isDeletePressed) {
if (event.detail < 2) return;
if (settings.store.requireModifier && !event.ctrlKey && !event.shiftKey) return;
if (channel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return;
if (isMe) {
if (!settings.store.enableDoubleClickToEdit || EditStore.isEditing(channel.id, msg.id)) return;
@ -89,7 +89,7 @@ export default definePlugin({
showMentionToggle: channel.guild_id !== null
});
}
} else if (settings.store.enableDeleteOnClick && (isMe || PermissionStore.can(MANAGE_CHANNELS, channel))) {
} else if (settings.store.enableDeleteOnClick && (isMe || PermissionStore.can(PermissionsBits.MANAGE_MESSAGES, channel))) {
if (msg.deleted) {
FluxDispatcher.dispatch({
type: "MESSAGE_DELETE",

View File

@ -0,0 +1,7 @@
# OnePingPerDM
If unread messages are sent by a user in DMs multiple times, you'll only receive one audio ping. Read the messages to reset the limit
## Purpose
- Prevents ping audio spam in DMs
- Be able to distinguish more than one ping as multiple users
- Be less annoyed while gaming

View File

@ -0,0 +1,39 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2023 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { ChannelStore, ReadStateStore } from "@webpack/common";
import { Message } from "discord-types/general";
const enum ChannelType {
DM = 1,
GROUP_DM = 3
}
export default definePlugin({
name: "OnePingPerDM",
description: "If unread messages are sent by a user in DMs multiple times, you'll only receive one audio ping. Read the messages to reset the limit",
authors: [Devs.ProffDea],
patches: [{
find: ".getDesktopType()===",
replacement: [{
match: /if\((\i\.\i\.getDesktopType\(\)===\i\.\i\.NEVER)\){/,
replace: "if($1){if(!$self.isPrivateChannelRead(arguments[0]?.message))return;"
},
{
match: /sound:(\i\?\i:void 0,volume:\i,onClick:)/,
replace: "sound:!$self.isPrivateChannelRead(arguments[0]?.message)?undefined:$1"
}]
}],
isPrivateChannelRead(message: Message) {
const channelType = ChannelStore.getChannel(message.channel_id)?.type;
if (channelType !== ChannelType.DM && channelType !== ChannelType.GROUP_DM) {
return false;
}
return ReadStateStore.getOldestUnreadMessageId(message.channel_id) === message.id;
},
});

View File

@ -19,10 +19,7 @@
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findStoreLazy } from "@webpack";
import { GenericStore } from "@webpack/common";
const PoggerModeSettingsStore: GenericStore = findStoreLazy("PoggermodeSettingsStore");
import { FluxDispatcher } from "@webpack/common";
const enum Intensity {
Normal,
@ -61,9 +58,12 @@ export default definePlugin({
});
function setPoggerState(state: boolean) {
Object.assign(PoggerModeSettingsStore.__getLocalVars().state, {
enabled: state,
settingsVisible: state
FluxDispatcher.dispatch({
type: "POGGERMODE_SETTINGS_UPDATE",
settings: {
enabled: state,
settingsVisible: state
}
});
}
@ -101,5 +101,8 @@ function setSettings(intensity: Intensity) {
}
}
Object.assign(PoggerModeSettingsStore.__getLocalVars().state, state);
FluxDispatcher.dispatch({
type: "POGGERMODE_SETTINGS_UPDATE",
settings: state
});
}

View File

@ -0,0 +1,14 @@
# PermissionFreeWill
Removes the client-side restrictions that prevent editing channel permissions, such as permission lockouts ("Pretty sure
you don't want to do this") and onboarding requirements ("Making this change will make your server incompatible [...]")
## Warning
This plugin will let you create permissions in servers that **WILL** lock you out of channels until an administrator
can resolve it for you. Please be careful with the overwrites you are making and check carefully.
## Community Server Channels
Community Server channels (i.e., `#rules` and `#moderator-only`) are actually mandatory and their existence is enforced
by the API, therefore this plugin cannot remove the restrictions behind them.

View File

@ -0,0 +1,67 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2023 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
const settings = definePluginSettings({
lockout: {
type: OptionType.BOOLEAN,
default: true,
description: 'Bypass the permission lockout prevention ("Pretty sure you don\'t want to do this")',
restartNeeded: true
},
onboarding: {
type: OptionType.BOOLEAN,
default: true,
description: 'Bypass the onboarding requirements ("Making this change will make your server incompatible [...]")',
restartNeeded: true
}
});
export default definePlugin({
name: "PermissionFreeWill",
description: "Disables the client-side restrictions for channel permission management.",
authors: [Devs.lewisakura],
patches: [
// Permission lockout, just set the check to true
{
find: "Messages.SELF_DENY_PERMISSION_BODY",
replacement: [
{
match: /case"DENY":.{0,50}if\((?=\i\.\i\.can)/,
replace: "$&true||"
}
],
predicate: () => settings.store.lockout
},
// Onboarding, same thing but we need to prevent the check
{
find: "Messages.ONBOARDING_CHANNEL_THRESHOLD_WARNING",
replacement: [
{
match: /case 1:if\((?=!\i\.sent.{20,30}Messages\.CANNOT_CHANGE_CHANNEL_PERMS)/,
replace: "$&false&&"
}
],
predicate: () => settings.store.onboarding
},
// Onboarding deletion
{
find: "Messages.DELETE_DEFAULT_CHANNEL_BODY",
replacement: [
{
match: /if\((?=null!=\i.{5,20}Messages.DELETE_DEFAULT_CHANNEL_BODY)/,
replace: "$&false&&"
}
],
predicate: () => settings.store.onboarding
}
],
settings
});

View File

@ -126,7 +126,7 @@ function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
function makeContextMenuPatch(childId: string | string[], type?: MenuItemParentType): NavContextMenuPatchCallback {
return (children, props) => () => {
if (!props) return children;
if (!props || (type === MenuItemParentType.User && !props.user) || (type === MenuItemParentType.Guild && !props.guild)) return children;
const group = findGroupChildrenByChildId(childId, children);

View File

@ -2,4 +2,5 @@
Lets you preview your message before sending it.
![Example](https://i.imgur.com/etqbkzu.png)
![the plugin in action](https://github.com/Vendicated/Vencord/assets/45497981/3ce32860-e5cd-4ea2-bdab-e121f1703579)

View File

@ -0,0 +1,5 @@
# QuickMention
Adds a mention icon to the messages action bar
![](https://github.com/Vendicated/Vencord/assets/55940580/82d3fec7-4196-4917-b3c2-6e652b2aff9e)

View File

@ -20,7 +20,7 @@ import { addButton, removeButton } from "@api/MessagePopover";
import { Devs } from "@utils/constants";
import { insertTextIntoChatInputBox } from "@utils/discord";
import definePlugin from "@utils/types";
import { ChannelStore } from "@webpack/common";
import { ChannelStore, PermissionsBits, PermissionStore } from "@webpack/common";
export default definePlugin({
name: "QuickMention",
@ -30,11 +30,14 @@ export default definePlugin({
start() {
addButton("QuickMention", msg => {
const channel = ChannelStore.getChannel(msg.channel_id);
if (!PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return null;
return {
label: "Quick Mention",
icon: this.Icon,
message: msg,
channel: ChannelStore.getChannel(msg.channel_id),
channel,
onClick: () => insertTextIntoChatInputBox(`<@${msg.author.id}> `)
};
});

View File

@ -0,0 +1,6 @@
# QuickReply
Reply to (ctrl + up/down) and edit (ctrl + shift + up/down) messages via keybinds
![](https://github.com/Vendicated/Vencord/assets/55940580/df79a27a-6529-4c70-8870-3c17d3637e4f)

View File

@ -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, SelectedChannelStore, UserStore } from "@webpack/common";
import { ChannelStore, FluxDispatcher as Dispatcher, MessageStore, PermissionsBits, PermissionStore, SelectedChannelStore, UserStore } from "@webpack/common";
import { Message } from "discord-types/general";
const Kangaroo = findByPropsLazy("jumpToMessage");
@ -172,6 +172,8 @@ function shouldMention(message) {
// handle next/prev reply
function nextReply(isUp: boolean) {
const currChannel = ChannelStore.getChannel(SelectedChannelStore.getChannelId());
if (currChannel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, currChannel)) return;
const message = getNextMessage(isUp, true);
if (!message)
@ -179,7 +181,6 @@ function nextReply(isUp: boolean) {
type: "DELETE_PENDING_REPLY",
channelId: SelectedChannelStore.getChannelId(),
});
const channel = ChannelStore.getChannel(message.channel_id);
const meId = UserStore.getCurrentUser().id;
@ -196,21 +197,21 @@ function nextReply(isUp: boolean) {
// handle next/prev edit
function nextEdit(isUp: boolean) {
const currChannel = ChannelStore.getChannel(SelectedChannelStore.getChannelId());
if (currChannel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, currChannel)) return;
const message = getNextMessage(isUp, false);
if (!message)
Dispatcher.dispatch({
return Dispatcher.dispatch({
type: "MESSAGE_END_EDIT",
channelId: SelectedChannelStore.getChannelId()
});
else {
Dispatcher.dispatch({
type: "MESSAGE_START_EDIT",
channelId: message.channel_id,
messageId: message.id,
content: message.content,
_isQuickEdit: true
});
jumpIfOffScreen(message.channel_id, message.id);
}
Dispatcher.dispatch({
type: "MESSAGE_START_EDIT",
channelId: message.channel_id,
messageId: message.id,
content: message.content,
_isQuickEdit: true
});
jumpIfOffScreen(message.channel_id, message.id);
}

View File

@ -16,6 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { DeleteIcon } from "@components/Icons";
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
import { Tooltip } from "@webpack/common";
@ -31,10 +32,7 @@ export function DeleteButton({ onClick }: { onClick(): void; }) {
className={classes(iconClasses.button, iconClasses.dangerous)}
onClick={onClick}
>
<svg width="16" height="16" viewBox="0 0 20 20">
<path fill="currentColor" d="M15 3.999V2H9V3.999H3V5.999H21V3.999H15Z" />
<path fill="currentColor" d="M5 6.99902V18.999C5 20.101 5.897 20.999 7 20.999H17C18.103 20.999 19 20.101 19 18.999V6.99902H5ZM11 17H9V11H11V17ZM15 17H13V11H15V17Z" />
</svg>
<DeleteIcon width="20" height="20" />
</div>
)}
</Tooltip>
@ -50,8 +48,11 @@ export function ReportButton({ onClick }: { onClick(): void; }) {
className={iconClasses.button}
onClick={onClick}
>
<svg width="16" height="16" viewBox="0 0 20 20">
<path fill="currentColor" d="M20,6.002H14V3.002C14,2.45 13.553,2.002 13,2.002H4C3.447,2.002 3,2.45 3,3.002V22.002H5V14.002H10.586L8.293,16.295C8.007,16.581 7.922,17.011 8.076,17.385C8.23,17.759 8.596,18.002 9,18.002H20C20.553,18.002 21,17.554 21,17.002V7.002C21,6.45 20.553,6.002 20,6.002Z" />
<svg width="20" height="20" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M20,6.002H14V3.002C14,2.45 13.553,2.002 13,2.002H4C3.447,2.002 3,2.45 3,3.002V22.002H5V14.002H10.586L8.293,16.295C8.007,16.581 7.922,17.011 8.076,17.385C8.23,17.759 8.596,18.002 9,18.002H20C20.553,18.002 21,17.554 21,17.002V7.002C21,6.45 20.553,6.002 20,6.002Z"
/>
</svg>
</div>
)}

View File

@ -43,7 +43,7 @@ export default LazyComponent(() => {
p("container", "isHeader"),
p("avatar", "zalgo"),
p("button", "wrapper", "selected"),
p("botTag")
p("botTag", "botTagRegular")
);
const dateFormat = new Intl.DateTimeFormat();
@ -94,7 +94,7 @@ export default LazyComponent(() => {
className={classes(avatar, clickable)}
onClick={openModal}
src={review.sender.profilePhoto || "/assets/1f0bfc0865d324c2587920a7d80c609b.png?size=128"}
style={{ left: "0px" }}
style={{ left: "0px", zIndex: 0 }}
/>
<div style={{ display: "inline-flex", justifyContent: "center", alignItems: "center" }}>
<span

View File

@ -2,4 +2,5 @@
Adds a reply button to search results.
![Screenshot](https://i.imgur.com/SjIEHpw.png)
![the plugin in action](https://github.com/Vendicated/Vencord/assets/45497981/07e741d3-0f97-4e5c-82b0-80712ecf2cbb)

View File

@ -17,23 +17,22 @@
*/
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
import { ReplyIcon } from "@components/Icons";
import { Devs } from "@utils/constants";
import { LazyComponent } from "@utils/react";
import definePlugin from "@utils/types";
import { findByCode, findByCodeLazy } from "@webpack";
import { ChannelStore, i18n, Menu, SelectedChannelStore } from "@webpack/common";
import { findByCodeLazy } from "@webpack";
import { ChannelStore, i18n, Menu, PermissionsBits, PermissionStore, SelectedChannelStore } from "@webpack/common";
import { Message } from "discord-types/general";
const ReplyIcon = LazyComponent(() => findByCode("M10 8.26667V4L3 11.4667L10 18.9333V14.56C15 14.56 18.5 16.2667 21 20C20 14.6667 17 9.33333 10 8.26667Z"));
const replyFn = findByCodeLazy("showMentionToggle", "TEXTAREA_FOCUS", "shiftKey");
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => () => {
// make sure the message is in the selected channel
if (SelectedChannelStore.getChannelId() !== message.channel_id) return;
const channel = ChannelStore.getChannel(message?.channel_id);
if (!channel) return;
if (channel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return;
// dms and group chats
const dmGroup = findGroupChildrenByChildId("pin", children);

Some files were not shown because too many files have changed in this diff Show More