Compare commits
13 Commits
v1.4.7
...
serverProf
Author | SHA1 | Date | |
---|---|---|---|
|
95b12f109a | ||
|
f40ab912eb | ||
|
700301ffbb | ||
|
d92894697b | ||
|
47569d2ffa | ||
|
d3b18bbcd2 | ||
|
eeedc531a3 | ||
|
59a2b834a6 | ||
|
1cfeaf77c1 | ||
|
1757d17661 | ||
|
9485d2457a | ||
|
3fd2fc1d61 | ||
|
49bc6b8fd6 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -38,7 +38,7 @@ jobs:
|
|||||||
run: pnpm build --standalone
|
run: pnpm build --standalone
|
||||||
|
|
||||||
- name: Generate plugin list
|
- name: Generate plugin list
|
||||||
run: pnpm generatePluginJson dist/plugins.json dist/plugin-readmes.json
|
run: pnpm generatePluginJson dist/plugins.json
|
||||||
|
|
||||||
- name: Clean up obsolete files
|
- name: Clean up obsolete files
|
||||||
run: |
|
run: |
|
||||||
|
@ -65,7 +65,7 @@ Also pay attention to the following:
|
|||||||
- Match any but a guaranteed terminating character: `[^;]+`, for example to match the entire assigned value in `var a=b||c||func();`,
|
- Match any but a guaranteed terminating character: `[^;]+`, for example to match the entire assigned value in `var a=b||c||func();`,
|
||||||
`var .{1,2}=([^;]+);`
|
`var .{1,2}=([^;]+);`
|
||||||
- If you don't care about that part, just match a bunch of chars: `.{0,50}`, for example to extract the variable "b" in `createElement("div",{a:"foo",c:"bar"},b)`, `createElement\("div".{0,30},(.{1,2})\),`. Note the `.{0,30}`, this is essentially the same as `.+`, but safer as you can't end up accidently eating thousands of characters
|
- If you don't care about that part, just match a bunch of chars: `.{0,50}`, for example to extract the variable "b" in `createElement("div",{a:"foo",c:"bar"},b)`, `createElement\("div".{0,30},(.{1,2})\),`. Note the `.{0,30}`, this is essentially the same as `.+`, but safer as you can't end up accidently eating thousands of characters
|
||||||
- Additionally, as you might have noticed, all of the above approaches use regex groups (`(...)`) to capture the variable name. You can then use those groups in your replacement to access those variables dynamically
|
- Additionally, as you might have noticed, all of the appove approaches use regex groups (`(...)`) to capture the variable name. You can then use those groups in your replacement to access those variables dynamically
|
||||||
|
|
||||||
#### "replace"
|
#### "replace"
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ Then fully close Discord from your taskbar or task manager, and restart it. Venc
|
|||||||
|
|
||||||
If you're using Discord already, go into the `Updater` tab in settings.
|
If you're using Discord already, go into the `Updater` tab in settings.
|
||||||
|
|
||||||
Sometimes it may be necessary to manually update if the GUI updater fails.
|
Sometimes it may be neccessary to manually update if the GUI updater fails.
|
||||||
|
|
||||||
To pull latest changes:
|
To pull latest changes:
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "vencord",
|
"name": "vencord",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"version": "1.4.7",
|
"version": "1.4.5",
|
||||||
"description": "The cutest Discord client mod",
|
"description": "The cutest Discord client mod",
|
||||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
@ -165,11 +165,7 @@ async function parseFile(fileName: string) {
|
|||||||
data.target = target as any;
|
data.target = target as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
let readme = "";
|
return data;
|
||||||
try {
|
|
||||||
readme = readFileSync(join(fileName, "..", "README.md"), "utf-8");
|
|
||||||
} catch { }
|
|
||||||
return [data, readme] as const;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw fail("no default export called 'definePlugin' found");
|
throw fail("no default export called 'definePlugin' found");
|
||||||
@ -198,24 +194,18 @@ function isPluginFile({ name }: { name: string; }) {
|
|||||||
(async () => {
|
(async () => {
|
||||||
parseDevs();
|
parseDevs();
|
||||||
|
|
||||||
const plugins = [] as PluginData[];
|
const plugins = ["src/plugins", "src/plugins/_core"].flatMap(dir =>
|
||||||
const readmes = {} as Record<string, string>;
|
|
||||||
|
|
||||||
await Promise.all(["src/plugins", "src/plugins/_core"].flatMap(dir =>
|
|
||||||
readdirSync(dir, { withFileTypes: true })
|
readdirSync(dir, { withFileTypes: true })
|
||||||
.filter(isPluginFile)
|
.filter(isPluginFile)
|
||||||
.map(async dirent => {
|
.map(async dirent =>
|
||||||
const [data, readme] = await parseFile(await getEntryPoint(dir, dirent));
|
parseFile(await getEntryPoint(dir, dirent))
|
||||||
plugins.push(data);
|
)
|
||||||
if (readme) readmes[data.name] = readme;
|
);
|
||||||
})
|
|
||||||
));
|
|
||||||
|
|
||||||
const data = JSON.stringify(plugins);
|
const data = JSON.stringify(await Promise.all(plugins));
|
||||||
|
|
||||||
if (process.argv.length > 3) {
|
if (process.argv.length > 2) {
|
||||||
writeFileSync(process.argv[2], data);
|
writeFileSync(process.argv[2], data);
|
||||||
writeFileSync(process.argv[3], JSON.stringify(readmes));
|
|
||||||
} else {
|
} else {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ page.on("console", async e => {
|
|||||||
plugin,
|
plugin,
|
||||||
type,
|
type,
|
||||||
id,
|
id,
|
||||||
match: regex.replace(/\[A-Za-z_\$\]\[\\w\$\]\*/g, "\\i"),
|
match: regex,
|
||||||
error: cause
|
error: cause
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2023 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { findByPropsLazy } from "@webpack";
|
|
||||||
import { Parser } from "@webpack/common";
|
|
||||||
|
|
||||||
const CodeContainerClasses = findByPropsLazy("markup", "codeContainer");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders code in a Discord codeblock
|
|
||||||
*/
|
|
||||||
export function CodeBlock(props: { content?: string, lang: string; }) {
|
|
||||||
return (
|
|
||||||
<div className={CodeContainerClasses.markup}>
|
|
||||||
{Parser.defaultRules.codeBlock.react(props, null, {})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2023 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import "./contributorModal.css";
|
|
||||||
|
|
||||||
import { useSettings } from "@api/Settings";
|
|
||||||
import { classNameFactory } from "@api/Styles";
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { DevsById } from "@utils/constants";
|
|
||||||
import { fetchUserProfile, getTheme, Theme } from "@utils/discord";
|
|
||||||
import { ModalContent, ModalRoot, openModal } from "@utils/modal";
|
|
||||||
import { Forms, MaskedLink, showToast, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common";
|
|
||||||
import { User } from "discord-types/general";
|
|
||||||
|
|
||||||
import Plugins from "~plugins";
|
|
||||||
|
|
||||||
import { PluginCard } from ".";
|
|
||||||
|
|
||||||
const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg";
|
|
||||||
const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg";
|
|
||||||
const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg";
|
|
||||||
const GithubIconDark = "/assets/6a853b4c87fce386cbfef4a2efbacb09.svg";
|
|
||||||
|
|
||||||
const cl = classNameFactory("vc-author-modal-");
|
|
||||||
|
|
||||||
export function openContributorModal(user: User) {
|
|
||||||
openModal(modalProps =>
|
|
||||||
<ModalRoot {...modalProps}>
|
|
||||||
<ErrorBoundary>
|
|
||||||
<ModalContent className={cl("root")}>
|
|
||||||
<ContributorModal user={user} />
|
|
||||||
</ModalContent>
|
|
||||||
</ErrorBoundary>
|
|
||||||
</ModalRoot>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function GithubIcon() {
|
|
||||||
const src = getTheme() === Theme.Light ? GithubIconLight : GithubIconDark;
|
|
||||||
return <img src={src} alt="GitHub" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
function WebsiteIcon() {
|
|
||||||
const src = getTheme() === Theme.Light ? WebsiteIconLight : WebsiteIconDark;
|
|
||||||
return <img src={src} alt="Website" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ContributorModal({ user }: { user: User; }) {
|
|
||||||
useSettings();
|
|
||||||
|
|
||||||
const profile = useStateFromStores([UserProfileStore], () => UserProfileStore.getUserProfile(user.id));
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!profile && !user.bot && user.id)
|
|
||||||
fetchUserProfile(user.id);
|
|
||||||
}, [user.id]);
|
|
||||||
|
|
||||||
const githubName = profile?.connectedAccounts?.find(a => a.type === "github")?.name;
|
|
||||||
const website = profile?.connectedAccounts?.find(a => a.type === "domain")?.name;
|
|
||||||
|
|
||||||
const plugins = useMemo(() => {
|
|
||||||
const allPlugins = Object.values(Plugins);
|
|
||||||
const pluginsByAuthor = DevsById[user.id]
|
|
||||||
? allPlugins.filter(p => p.authors.includes(DevsById[user.id]))
|
|
||||||
: allPlugins.filter(p => p.authors.some(a => a.name === user.username));
|
|
||||||
|
|
||||||
return pluginsByAuthor
|
|
||||||
.filter(p => !p.name.endsWith("API"))
|
|
||||||
.sort((a, b) => Number(a.required ?? false) - Number(b.required ?? false));
|
|
||||||
}, [user.id, user.username]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={cl("header")}>
|
|
||||||
<img
|
|
||||||
className={cl("avatar")}
|
|
||||||
src={user.getAvatarURL(void 0, 512, true)}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<Forms.FormTitle tag="h2" className={cl("name")}>{user.username}</Forms.FormTitle>
|
|
||||||
|
|
||||||
<div className={cl("links")}>
|
|
||||||
{website && (
|
|
||||||
<MaskedLink
|
|
||||||
href={"https://" + website}
|
|
||||||
>
|
|
||||||
<WebsiteIcon />
|
|
||||||
</MaskedLink>
|
|
||||||
)}
|
|
||||||
{githubName && (
|
|
||||||
<MaskedLink href={`https://github.com/${githubName}`}>
|
|
||||||
<GithubIcon />
|
|
||||||
</MaskedLink>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={cl("plugins")}>
|
|
||||||
{plugins.map(p =>
|
|
||||||
<PluginCard
|
|
||||||
key={p.name}
|
|
||||||
plugin={p}
|
|
||||||
disabled={p.required ?? false}
|
|
||||||
onRestartNeeded={() => showToast("Restart to apply changes!")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -18,16 +18,17 @@
|
|||||||
|
|
||||||
import { generateId } from "@api/Commands";
|
import { generateId } from "@api/Commands";
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { proxyLazy } from "@utils/lazy";
|
import { proxyLazy } from "@utils/lazy";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes, isObjectEmpty } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize } from "@utils/modal";
|
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize } from "@utils/modal";
|
||||||
import { LazyComponent } from "@utils/react";
|
import { LazyComponent } from "@utils/react";
|
||||||
import { OptionType, Plugin } from "@utils/types";
|
import { OptionType, Plugin } from "@utils/types";
|
||||||
import { findByCode, findByPropsLazy } from "@webpack";
|
import { findByCode, findByPropsLazy } from "@webpack";
|
||||||
import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common";
|
import { Button, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
import { User } from "discord-types/general";
|
||||||
import { Constructor } from "type-fest";
|
import { Constructor } from "type-fest";
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ import {
|
|||||||
SettingSliderComponent,
|
SettingSliderComponent,
|
||||||
SettingTextComponent
|
SettingTextComponent
|
||||||
} from "./components";
|
} from "./components";
|
||||||
import { openContributorModal } from "./ContributorModal";
|
import hideBotTagStyle from "./userPopoutHideBotTag.css?managed";
|
||||||
|
|
||||||
const UserSummaryItem = LazyComponent(() => findByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers"));
|
const UserSummaryItem = LazyComponent(() => findByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers"));
|
||||||
const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
|
const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
|
||||||
@ -88,19 +89,30 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
|||||||
|
|
||||||
const canSubmit = () => Object.values(errors).every(e => !e);
|
const canSubmit = () => Object.values(errors).every(e => !e);
|
||||||
|
|
||||||
const hasSettings = Boolean(pluginSettings && plugin.options && !isObjectEmpty(plugin.options));
|
const hasSettings = Boolean(pluginSettings && plugin.options);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
enableStyle(hideBotTagStyle);
|
||||||
|
|
||||||
|
let originalUser: User;
|
||||||
(async () => {
|
(async () => {
|
||||||
for (const user of plugin.authors.slice(0, 6)) {
|
for (const user of plugin.authors.slice(0, 6)) {
|
||||||
const author = user.id
|
const author = user.id
|
||||||
? await UserUtils.fetchUser(`${user.id}`)
|
? await UserUtils.fetchUser(`${user.id}`)
|
||||||
|
// only show name & pfp and no actions so users cannot harass plugin devs for support (send dms, add as friend, etc)
|
||||||
|
.then(u => (originalUser = u, makeDummyUser(u)))
|
||||||
.catch(() => makeDummyUser({ username: user.name }))
|
.catch(() => makeDummyUser({ username: user.name }))
|
||||||
: makeDummyUser({ username: user.name });
|
: makeDummyUser({ username: user.name });
|
||||||
|
|
||||||
setAuthors(a => [...a, author]);
|
setAuthors(a => [...a, author]);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disableStyle(hideBotTagStyle);
|
||||||
|
if (originalUser)
|
||||||
|
FluxDispatcher.dispatch({ type: "USER_UPDATE", user: originalUser });
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
async function saveAndClose() {
|
async function saveAndClose() {
|
||||||
@ -202,19 +214,6 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
|||||||
showDefaultAvatarsForNullUsers
|
showDefaultAvatarsForNullUsers
|
||||||
showUserPopout
|
showUserPopout
|
||||||
renderMoreUsers={renderMoreUsers}
|
renderMoreUsers={renderMoreUsers}
|
||||||
renderUser={(user: User) => (
|
|
||||||
<Clickable
|
|
||||||
className={AvatarStyles.clickableAvatar}
|
|
||||||
onClick={() => openContributorModal(user)}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
className={AvatarStyles.avatar}
|
|
||||||
src={user.getAvatarURL(void 0, 80, true)}
|
|
||||||
alt={user.username}
|
|
||||||
title={user.username}
|
|
||||||
/>
|
|
||||||
</Clickable>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
.vc-author-modal-root {
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-author-modal-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-author-modal-name {
|
|
||||||
text-transform: none;
|
|
||||||
flex-grow: 0;
|
|
||||||
background: var(--background-tertiary);
|
|
||||||
border-radius: 0 9999px 9999px 0;
|
|
||||||
padding: 6px 0.8em 6px 0.5em;
|
|
||||||
font-size: 20px;
|
|
||||||
height: 20px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-author-modal-name::before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
width: 16px;
|
|
||||||
background: var(--background-tertiary);
|
|
||||||
z-index: -1;
|
|
||||||
left: -16px;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-author-modal-avatar {
|
|
||||||
height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-author-modal-links {
|
|
||||||
margin-left: auto;
|
|
||||||
display: flex;
|
|
||||||
gap: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-author-modal-links img {
|
|
||||||
height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 4px solid var(--background-tertiary);
|
|
||||||
box-sizing: border-box
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-author-modal-plugins {
|
|
||||||
display: grid;
|
|
||||||
gap: 0.5em;
|
|
||||||
}
|
|
@ -28,7 +28,7 @@ import { SettingsTab } from "@components/VencordSettings/shared";
|
|||||||
import { ChangeList } from "@utils/ChangeList";
|
import { ChangeList } from "@utils/ChangeList";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes, isObjectEmpty } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { openModalLazy } from "@utils/modal";
|
import { openModalLazy } from "@utils/modal";
|
||||||
import { LazyComponent, useAwaiter } from "@utils/react";
|
import { LazyComponent, useAwaiter } from "@utils/react";
|
||||||
import { Plugin } from "@utils/types";
|
import { Plugin } from "@utils/types";
|
||||||
@ -91,7 +91,7 @@ interface PluginCardProps extends React.HTMLProps<HTMLDivElement> {
|
|||||||
isNew?: boolean;
|
isNew?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) {
|
function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) {
|
||||||
const settings = Settings.plugins[plugin.name];
|
const settings = Settings.plugins[plugin.name];
|
||||||
|
|
||||||
const isEnabled = () => settings.enabled ?? false;
|
const isEnabled = () => settings.enabled ?? false;
|
||||||
@ -161,7 +161,7 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on
|
|||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
infoButton={
|
infoButton={
|
||||||
<button role="switch" onClick={() => openModal()} className={classes(ButtonClasses.button, cl("info-button"))}>
|
<button role="switch" onClick={() => openModal()} className={classes(ButtonClasses.button, cl("info-button"))}>
|
||||||
{plugin.options && !isObjectEmpty(plugin.options)
|
{plugin.options
|
||||||
? <CogWheel />
|
? <CogWheel />
|
||||||
: <InfoIcon width="24" height="24" />}
|
: <InfoIcon width="24" height="24" />}
|
||||||
</button>
|
</button>
|
||||||
|
3
src/components/PluginSettings/userPopoutHideBotTag.css
Normal file
3
src/components/PluginSettings/userPopoutHideBotTag.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[class|="userPopoutOuter"] [class*="botTag"] {
|
||||||
|
display: none;
|
||||||
|
}
|
@ -17,7 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||||
import { CodeBlock } from "@components/CodeBlock";
|
|
||||||
import { debounce } from "@utils/debounce";
|
import { debounce } from "@utils/debounce";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
|
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
|
||||||
@ -300,7 +299,7 @@ function PatchHelper() {
|
|||||||
{!!(find && match && replacement) && (
|
{!!(find && match && replacement) && (
|
||||||
<>
|
<>
|
||||||
<Forms.FormTitle className={Margins.top20}>Code</Forms.FormTitle>
|
<Forms.FormTitle className={Margins.top20}>Code</Forms.FormTitle>
|
||||||
<CodeBlock lang="js" content={code} />
|
<div style={{ userSelect: "text" }}>{Parser.parse(makeCodeblock(code, "ts"))}</div>
|
||||||
<Button onClick={() => Clipboard.copy(code)}>Copy to Clipboard</Button>
|
<Button onClick={() => Clipboard.copy(code)}>Copy to Clipboard</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
transition: 0.1s ease-out;
|
transition: 0.1s ease-out;
|
||||||
transition-property: box-shadow, transform, background, opacity;
|
transition-property: box-shadow, transform, background, opacity;
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-addon-card-disabled {
|
.vc-addon-card-disabled {
|
||||||
|
@ -49,7 +49,7 @@ export default definePlugin({
|
|||||||
replace: "$1,vcProps=$2$3+(vcProps.channel.nsfw?' vc-nsfw-img':'')"
|
replace: "$1,vcProps=$2$3+(vcProps.channel.nsfw?' vc-nsfw-img':'')"
|
||||||
}, {
|
}, {
|
||||||
match: /(\.renderAttachments=.+?(.)=this\.props)(.+?\.embedWrapper)/g,
|
match: /(\.renderAttachments=.+?(.)=this\.props)(.+?\.embedWrapper)/g,
|
||||||
replace: "$1,vcProps=$2$3+(vcProps.nsfw?' vc-nsfw-img':'')"
|
replace: "$1,vcProps=$2$3+(vcProps.channel.nsfw?' vc-nsfw-img':'')"
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -136,5 +136,4 @@ export const defaultRules = [
|
|||||||
"utm_term",
|
"utm_term",
|
||||||
"si@open.spotify.com",
|
"si@open.spotify.com",
|
||||||
"igshid",
|
"igshid",
|
||||||
"share_id@reddit.com",
|
|
||||||
];
|
];
|
||||||
|
@ -49,7 +49,7 @@ export default definePlugin({
|
|||||||
await this.buildCss();
|
await this.buildCss();
|
||||||
|
|
||||||
addButton("HideAttachments", msg => {
|
addButton("HideAttachments", msg => {
|
||||||
if (!msg.attachments.length && !msg.embeds.length && !msg.stickerItems.length) return null;
|
if (!msg.attachments.length && !msg.embeds.length) return null;
|
||||||
|
|
||||||
const isHidden = hiddenMessages.has(msg.id);
|
const isHidden = hiddenMessages.has(msg.id);
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ export default definePlugin({
|
|||||||
async buildCss() {
|
async buildCss() {
|
||||||
const elements = [...hiddenMessages].map(id => `#message-accessories-${id}`).join(",");
|
const elements = [...hiddenMessages].map(id => `#message-accessories-${id}`).join(",");
|
||||||
style.textContent = `
|
style.textContent = `
|
||||||
:is(${elements}) :is([class*="embedWrapper"], [class*="clickableSticker"]) {
|
:is(${elements}) [class*="embedWrapper"] {
|
||||||
/* important is not necessary, but add it to make sure bad themes won't break it */
|
/* important is not necessary, but add it to make sure bad themes won't break it */
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,7 @@ const quotes = [
|
|||||||
"hd{b${",
|
"hd{b${",
|
||||||
"<;vqkijbq33271:56<3799?24944:",
|
"<;vqkijbq33271:56<3799?24944:",
|
||||||
"Thof$lu'ofdn,!qsefc'az*bnrcma+&Om{o+iu\"`khct$)bnrd\"bcdoi&",
|
"Thof$lu'ofdn,!qsefc'az*bnrcma+&Om{o+iu\"`khct$)bnrd\"bcdoi&",
|
||||||
"snofplkb{)c'r\"lod'|f*aurv#cpno`abchijklmno",
|
"snofplkb{)c'r\"lod'|f*aurv#cpno`abchijklmno"
|
||||||
"Wdn`khc'|f*eghl{%"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
|
@ -30,9 +30,6 @@ const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
|
|||||||
getProps(guildId: string, channelId: string): { groups: { count: number; id: string; }[]; };
|
getProps(guildId: string, channelId: string): { groups: { count: number; id: string; }[]; };
|
||||||
};
|
};
|
||||||
|
|
||||||
const sharedIntlNumberFormat = new Intl.NumberFormat();
|
|
||||||
const numberFormat = (value: number) => sharedIntlNumberFormat.format(value);
|
|
||||||
|
|
||||||
function MemberCount() {
|
function MemberCount() {
|
||||||
const { id: channelId, guild_id: guildId } = useStateFromStores([SelectedChannelStore], () => getCurrentChannel());
|
const { id: channelId, guild_id: guildId } = useStateFromStores([SelectedChannelStore], () => getCurrentChannel());
|
||||||
const { groups } = useStateFromStores(
|
const { groups } = useStateFromStores(
|
||||||
@ -60,7 +57,7 @@ function MemberCount() {
|
|||||||
alignContent: "center",
|
alignContent: "center",
|
||||||
gap: 0
|
gap: 0
|
||||||
}}>
|
}}>
|
||||||
<Tooltip text={`${numberFormat(online)} online in this channel`} position="bottom">
|
<Tooltip text={`${online} Online in this Channel`} position="bottom">
|
||||||
{props => (
|
{props => (
|
||||||
<div {...props}>
|
<div {...props}>
|
||||||
<span
|
<span
|
||||||
@ -73,11 +70,11 @@ function MemberCount() {
|
|||||||
marginRight: "0.5em"
|
marginRight: "0.5em"
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span style={{ color: "var(--green-360)" }}>{numberFormat(online)}</span>
|
<span style={{ color: "var(--green-360)" }}>{online}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip text={`${numberFormat(total)} total server members`} position="bottom">
|
<Tooltip text={`${total} Total Server Members`} position="bottom">
|
||||||
{props => (
|
{props => (
|
||||||
<div {...props}>
|
<div {...props}>
|
||||||
<span
|
<span
|
||||||
@ -91,7 +88,7 @@ function MemberCount() {
|
|||||||
marginLeft: "1em"
|
marginLeft: "1em"
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span style={{ color: "var(--primary-400)" }}>{numberFormat(total)}</span>
|
<span style={{ color: "var(--primary-400)" }}>{total}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -169,14 +169,21 @@ export default definePlugin({
|
|||||||
try {
|
try {
|
||||||
if (cache == null || (!isBulk && !cache.has(data.id))) return cache;
|
if (cache == null || (!isBulk && !cache.has(data.id))) return cache;
|
||||||
|
|
||||||
const mutate = (id: string) => {
|
const { ignoreBots, ignoreSelf, ignoreUsers, ignoreChannels, ignoreGuilds } = Settings.plugins.MessageLogger;
|
||||||
|
const myId = UserStore.getCurrentUser().id;
|
||||||
|
|
||||||
|
function mutate(id: string) {
|
||||||
const msg = cache.get(id);
|
const msg = cache.get(id);
|
||||||
if (!msg) return;
|
if (!msg) return;
|
||||||
|
|
||||||
const EPHEMERAL = 64;
|
const EPHEMERAL = 64;
|
||||||
const shouldIgnore = data.mlDeleted ||
|
const shouldIgnore = data.mlDeleted ||
|
||||||
(msg.flags & EPHEMERAL) === EPHEMERAL ||
|
(msg.flags & EPHEMERAL) === EPHEMERAL ||
|
||||||
this.shouldIgnore(msg);
|
ignoreBots && msg.author?.bot ||
|
||||||
|
ignoreSelf && msg.author?.id === myId ||
|
||||||
|
ignoreUsers.includes(msg.author?.id) ||
|
||||||
|
ignoreChannels.includes(msg.channel_id) ||
|
||||||
|
ignoreGuilds.includes(ChannelStore.getChannel(msg.channel_id)?.guild_id);
|
||||||
|
|
||||||
if (shouldIgnore) {
|
if (shouldIgnore) {
|
||||||
cache = cache.remove(id);
|
cache = cache.remove(id);
|
||||||
@ -185,7 +192,7 @@ export default definePlugin({
|
|||||||
.set("deleted", true)
|
.set("deleted", true)
|
||||||
.set("attachments", m.attachments.map(a => (a.deleted = true, a))));
|
.set("attachments", m.attachments.map(a => (a.deleted = true, a))));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if (isBulk) {
|
if (isBulk) {
|
||||||
data.ids.forEach(mutate);
|
data.ids.forEach(mutate);
|
||||||
@ -198,18 +205,6 @@ export default definePlugin({
|
|||||||
return cache;
|
return cache;
|
||||||
},
|
},
|
||||||
|
|
||||||
shouldIgnore(message: any) {
|
|
||||||
const { ignoreBots, ignoreSelf, ignoreUsers, ignoreChannels, ignoreGuilds } = Settings.plugins.MessageLogger;
|
|
||||||
const myId = UserStore.getCurrentUser().id;
|
|
||||||
|
|
||||||
return ignoreBots && message.author?.bot ||
|
|
||||||
ignoreSelf && message.author?.id === myId ||
|
|
||||||
ignoreUsers.includes(message.author?.id) ||
|
|
||||||
ignoreChannels.includes(message.channel_id) ||
|
|
||||||
ignoreChannels.includes(ChannelStore.getChannel(message.channel_id)?.parent_id) ||
|
|
||||||
ignoreGuilds.includes(ChannelStore.getChannel(message.channel_id)?.guild_id);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Based on canary 9ab8626bcebceaea6da570b9c586172d02b9c996
|
// Based on canary 9ab8626bcebceaea6da570b9c586172d02b9c996
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
@ -242,7 +237,7 @@ export default definePlugin({
|
|||||||
match: /(MESSAGE_UPDATE:function\((\w)\).+?)\.update\((\w)/,
|
match: /(MESSAGE_UPDATE:function\((\w)\).+?)\.update\((\w)/,
|
||||||
replace: "$1" +
|
replace: "$1" +
|
||||||
".update($3,m =>" +
|
".update($3,m =>" +
|
||||||
" (($2.message.flags & 64) === 64 || $self.shouldIgnore($2.message)) ? m :" +
|
" (($2.message.flags & 64) === 64 || (Vencord.Settings.plugins.MessageLogger.ignoreBots && $2.message.author?.bot) || (Vencord.Settings.plugins.MessageLogger.ignoreSelf && $2.message.author?.id === Vencord.Webpack.Common.UserStore.getCurrentUser().id)) ? m :" +
|
||||||
" $2.message.content !== m.editHistory?.[0]?.content && $2.message.content !== m.content ?" +
|
" $2.message.content !== m.editHistory?.[0]?.content && $2.message.content !== m.content ?" +
|
||||||
" m.set('editHistory',[...(m.editHistory || []), $self.makeEdit($2.message, m)]) :" +
|
" m.set('editHistory',[...(m.editHistory || []), $self.makeEdit($2.message, m)]) :" +
|
||||||
" m" +
|
" m" +
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2023 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Devs } from "@utils/constants";
|
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
|
||||||
import { React, Tooltip } from "@webpack/common";
|
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
|
||||||
loop: {
|
|
||||||
description: "Whether to make the PiP video loop or not",
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
default: true,
|
|
||||||
restartNeeded: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default definePlugin({
|
|
||||||
name: "PictureInPicture",
|
|
||||||
description: "Adds picture in picture to videos (next to the Download button)",
|
|
||||||
authors: [Devs.Lumap],
|
|
||||||
settings,
|
|
||||||
|
|
||||||
patches: [
|
|
||||||
{
|
|
||||||
find: ".onRemoveAttachment,",
|
|
||||||
replacement: {
|
|
||||||
match: /\.nonMediaAttachment.{0,10}children:\[(\i),/,
|
|
||||||
replace: "$&$1&&$self.renderPiPButton(),"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
renderPiPButton: ErrorBoundary.wrap(() => {
|
|
||||||
return (
|
|
||||||
<Tooltip text="Toggle Picture in Picture">
|
|
||||||
{tooltipProps => (
|
|
||||||
<div
|
|
||||||
{...tooltipProps}
|
|
||||||
role="button"
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
paddingTop: "4px",
|
|
||||||
paddingLeft: "4px",
|
|
||||||
paddingRight: "4px",
|
|
||||||
}}
|
|
||||||
onClick={e => {
|
|
||||||
const video = e.currentTarget.parentNode!.parentNode!.querySelector("video")!;
|
|
||||||
const videoClone = document.body.appendChild(video.cloneNode(true)) as HTMLVideoElement;
|
|
||||||
|
|
||||||
videoClone.loop = settings.store.loop;
|
|
||||||
videoClone.style.display = "none";
|
|
||||||
videoClone.onleavepictureinpicture = () => videoClone.remove();
|
|
||||||
|
|
||||||
function launchPiP() {
|
|
||||||
videoClone.currentTime = video.currentTime;
|
|
||||||
videoClone.requestPictureInPicture();
|
|
||||||
video.pause();
|
|
||||||
videoClone.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoClone.readyState === 4 /* HAVE_ENOUGH_DATA */)
|
|
||||||
launchPiP();
|
|
||||||
else
|
|
||||||
videoClone.onloadedmetadata = launchPiP;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg width="24px" height="24px" viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
fill="var(--interactive-normal)"
|
|
||||||
d="M21 3a1 1 0 0 1 1 1v7h-2V5H4v14h6v2H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h18zm0 10a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-8a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1h8zm-1 2h-6v4h6v-4z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}, { noop: true })
|
|
||||||
});
|
|
@ -122,14 +122,6 @@ export default definePlugin({
|
|||||||
// ....concat(pins).concat(toArray(channelIds).filter(c => !isPinned(c)))
|
// ....concat(pins).concat(toArray(channelIds).filter(c => !isPinned(c)))
|
||||||
replace: ".concat($self.getSnapshot()).concat($2.filter(c=>!$self.isPinned(c)))"
|
replace: ".concat($self.getSnapshot()).concat($2.filter(c=>!$self.isPinned(c)))"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
// fix alt+shift+up/down
|
|
||||||
{
|
|
||||||
find: '"alt+shift+down"',
|
|
||||||
replacement: {
|
|
||||||
match: /(?<=return \i===\i\.ME\?)\i\.\i\.getPrivateChannelIds\(\)/,
|
|
||||||
replace: "$self.getSnapshot().concat($&.filter(c=>!$self.isPinned(c)))"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,7 @@ import { sendBotMessage } from "@api/Commands";
|
|||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { Button, ButtonLooks, ButtonWrapperClasses, DraftStore, DraftType, SelectedChannelStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
|
import { Button, ButtonLooks, ButtonWrapperClasses, DraftStore, DraftType, SelectedChannelStore, Tooltip, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type: {
|
type: {
|
||||||
@ -31,9 +31,10 @@ interface Props {
|
|||||||
const getDraft = (channelId: string) => DraftStore.getDraft(channelId, DraftType.ChannelMessage);
|
const getDraft = (channelId: string) => DraftStore.getDraft(channelId, DraftType.ChannelMessage);
|
||||||
|
|
||||||
export function PreviewButton(chatBoxProps: Props) {
|
export function PreviewButton(chatBoxProps: Props) {
|
||||||
const channelId = SelectedChannelStore.getChannelId();
|
|
||||||
const draft = useStateFromStores([DraftStore], () => getDraft(channelId));
|
|
||||||
if (chatBoxProps.type.analyticsName !== "normal") return null;
|
if (chatBoxProps.type.analyticsName !== "normal") return null;
|
||||||
|
const channelId = SelectedChannelStore.getChannelId();
|
||||||
|
const draft = getDraft(channelId);
|
||||||
|
|
||||||
if (!draft) return null;
|
if (!draft) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -21,11 +21,14 @@ import { VENCORD_USER_AGENT } from "@utils/constants";
|
|||||||
import { debounce } from "@utils/debounce";
|
import { debounce } from "@utils/debounce";
|
||||||
import { getCurrentChannel } from "@utils/discord";
|
import { getCurrentChannel } from "@utils/discord";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { UserProfileStore, UserStore } from "@webpack/common";
|
import { findStoreLazy } from "@webpack";
|
||||||
|
import { UserStore } from "@webpack/common";
|
||||||
|
|
||||||
import { settings } from "./settings";
|
import { settings } from "./settings";
|
||||||
import { PronounCode, PronounMapping, PronounsResponse } from "./types";
|
import { PronounCode, PronounMapping, PronounsResponse } from "./types";
|
||||||
|
|
||||||
|
const UserProfileStore = findStoreLazy("UserProfileStore");
|
||||||
|
|
||||||
type PronounsWithSource = [string | null, string];
|
type PronounsWithSource = [string | null, string];
|
||||||
const EmptyPronouns: PronounsWithSource = [null, ""];
|
const EmptyPronouns: PronounsWithSource = [null, ""];
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ export default definePlugin({
|
|||||||
find: "window.webkitAudioContext",
|
find: "window.webkitAudioContext",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=\i\.acquire=function\((\i)\)\{return )navigator\.mediaDevices\.getUserMedia\(\1\)(?=\})/,
|
match: /(?<=\i\.acquire=function\((\i)\)\{return )navigator\.mediaDevices\.getUserMedia\(\1\)(?=\})/,
|
||||||
replace: "$&.then(stream => $self.connectRnnoise(stream, $1.audio))"
|
replace: m => `${m}.then(stream => $self.connectRnnoise(stream))`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -182,8 +182,7 @@ export default definePlugin({
|
|||||||
|
|
||||||
setEnabled,
|
setEnabled,
|
||||||
isEnabled: () => settings.store.isEnabled,
|
isEnabled: () => settings.store.isEnabled,
|
||||||
async connectRnnoise(stream: MediaStream, isAudio: boolean): Promise<MediaStream> {
|
async connectRnnoise(stream: MediaStream): Promise<MediaStream> {
|
||||||
if (!isAudio) return stream;
|
|
||||||
if (!settings.store.isEnabled) return stream;
|
if (!settings.store.isEnabled) return stream;
|
||||||
|
|
||||||
const audioCtx = new AudioContext();
|
const audioCtx = new AudioContext();
|
||||||
|
@ -27,12 +27,13 @@ import { copyWithToast } from "@utils/misc";
|
|||||||
import { LazyComponent } from "@utils/react";
|
import { LazyComponent } from "@utils/react";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByCode, findByCodeLazy, findByPropsLazy, findStoreLazy } from "@webpack";
|
import { findByCode, findByCodeLazy, findByPropsLazy, findStoreLazy } from "@webpack";
|
||||||
import { Text, Tooltip, UserProfileStore } from "@webpack/common";
|
import { Text, Tooltip } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
import { User } from "discord-types/general";
|
||||||
|
|
||||||
import { VerifiedIcon } from "./VerifiedIcon";
|
import { VerifiedIcon } from "./VerifiedIcon";
|
||||||
|
|
||||||
const Section = LazyComponent(() => findByCode("().lastSection"));
|
const Section = LazyComponent(() => findByCode("().lastSection"));
|
||||||
|
const UserProfileStore = findStoreLazy("UserProfileStore");
|
||||||
const ThemeStore = findStoreLazy("ThemeStore");
|
const ThemeStore = findStoreLazy("ThemeStore");
|
||||||
const platforms: { get(type: string): ConnectionPlatform; } = findByPropsLazy("isSupported", "getByUrl");
|
const platforms: { get(type: string): ConnectionPlatform; } = findByPropsLazy("isSupported", "getByUrl");
|
||||||
const getTheme: (user: User, displayProfile: any) => any = findByCodeLazy(',"--profile-gradient-primary-color"');
|
const getTheme: (user: User, displayProfile: any) => any = findByCodeLazy(',"--profile-gradient-primary-color"');
|
||||||
|
@ -1,35 +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 { Devs } from "@utils/constants";
|
|
||||||
import definePlugin from "@utils/types";
|
|
||||||
|
|
||||||
export default definePlugin({
|
|
||||||
name: "ShowTimeouts",
|
|
||||||
description: "Display member timeout icons in chat regardless of permissions.",
|
|
||||||
authors: [Devs.Dolfies],
|
|
||||||
patches: [
|
|
||||||
{
|
|
||||||
find: "showCommunicationDisabledStyles",
|
|
||||||
replacement: {
|
|
||||||
match: /&&\i\.\i\.canManageUser\(\i\.\i\.MODERATE_MEMBERS,\i\.author,\i\)/,
|
|
||||||
replace: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
@ -48,7 +48,7 @@ export default definePlugin({
|
|||||||
name: "vencord-debug",
|
name: "vencord-debug",
|
||||||
description: "Send Vencord Debug info",
|
description: "Send Vencord Debug info",
|
||||||
predicate: ctx => AllowedChannelIds.includes(ctx.channel.id),
|
predicate: ctx => AllowedChannelIds.includes(ctx.channel.id),
|
||||||
async execute() {
|
execute() {
|
||||||
const { RELEASE_CHANNEL } = window.GLOBAL_ENV;
|
const { RELEASE_CHANNEL } = window.GLOBAL_ENV;
|
||||||
|
|
||||||
const client = (() => {
|
const client = (() => {
|
||||||
@ -75,10 +75,6 @@ export default definePlugin({
|
|||||||
OpenAsar: "openasar" in window,
|
OpenAsar: "openasar" in window,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (IS_DISCORD_DESKTOP) {
|
|
||||||
info["Last Crash Reason"] = (await DiscordNative.processUtils.getLastCrash())?.rendererCrashReason ?? "N/A";
|
|
||||||
}
|
|
||||||
|
|
||||||
const debugInfo = `
|
const debugInfo = `
|
||||||
**Vencord Debug Info**
|
**Vencord Debug Info**
|
||||||
>>> ${Object.entries(info).map(([k, v]) => `${k}: ${v}`).join("\n")}
|
>>> ${Object.entries(info).map(([k, v]) => `${k}: ${v}`).join("\n")}
|
||||||
|
@ -80,9 +80,6 @@ export default definePlugin({
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
data,
|
|
||||||
|
|
||||||
settingsAboutComponent: () => {
|
settingsAboutComponent: () => {
|
||||||
return (
|
return (
|
||||||
<Link href="https://github.com/AutumnVN/usrbg#how-to-request-your-own-usrbg-banner">CLICK HERE TO GET YOUR OWN BANNER</Link>
|
<Link href="https://github.com/AutumnVN/usrbg#how-to-request-your-own-usrbg-banner">CLICK HERE TO GET YOUR OWN BANNER</Link>
|
||||||
@ -119,9 +116,7 @@ export default definePlugin({
|
|||||||
enableStyle(style);
|
enableStyle(style);
|
||||||
|
|
||||||
const res = await fetch(BASE_URL);
|
const res = await fetch(BASE_URL);
|
||||||
if (res.ok) {
|
if (res.ok)
|
||||||
data = await res.json();
|
data = await res.json();
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
|
||||||
import { addButton, removeButton } from "@api/MessagePopover";
|
import { addButton, removeButton } from "@api/MessagePopover";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { CodeBlock } from "@components/CodeBlock";
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
@ -27,12 +25,12 @@ import { Margins } from "@utils/margins";
|
|||||||
import { copyWithToast } from "@utils/misc";
|
import { copyWithToast } from "@utils/misc";
|
||||||
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { Button, ChannelStore, Forms, Menu, Text } from "@webpack/common";
|
import { Button, ChannelStore, Forms, Parser, Text } from "@webpack/common";
|
||||||
import { Message } from "discord-types/general";
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
|
|
||||||
const CopyIcon = () => {
|
const CopyIcon = () => {
|
||||||
return <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" width="18" height="18">
|
return <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" width="22" height="22">
|
||||||
<path d="M12.9297 3.25007C12.7343 3.05261 12.4154 3.05226 12.2196 3.24928L11.5746 3.89824C11.3811 4.09297 11.3808 4.40733 11.5739 4.60245L16.5685 9.64824C16.7614 9.84309 16.7614 10.1569 16.5685 10.3517L11.5739 15.3975C11.3808 15.5927 11.3811 15.907 11.5746 16.1017L12.2196 16.7507C12.4154 16.9477 12.7343 16.9474 12.9297 16.7499L19.2604 10.3517C19.4532 10.1568 19.4532 9.84314 19.2604 9.64832L12.9297 3.25007Z" />
|
<path d="M12.9297 3.25007C12.7343 3.05261 12.4154 3.05226 12.2196 3.24928L11.5746 3.89824C11.3811 4.09297 11.3808 4.40733 11.5739 4.60245L16.5685 9.64824C16.7614 9.84309 16.7614 10.1569 16.5685 10.3517L11.5739 15.3975C11.3808 15.5927 11.3811 15.907 11.5746 16.1017L12.2196 16.7507C12.4154 16.9477 12.7343 16.9474 12.9297 16.7499L19.2604 10.3517C19.4532 10.1568 19.4532 9.84314 19.2604 9.64832L12.9297 3.25007Z" />
|
||||||
<path d="M8.42616 4.60245C8.6193 4.40733 8.61898 4.09297 8.42545 3.89824L7.78047 3.24928C7.58466 3.05226 7.26578 3.05261 7.07041 3.25007L0.739669 9.64832C0.5469 9.84314 0.546901 10.1568 0.739669 10.3517L7.07041 16.7499C7.26578 16.9474 7.58465 16.9477 7.78047 16.7507L8.42545 16.1017C8.61898 15.907 8.6193 15.5927 8.42616 15.3975L3.43155 10.3517C3.23869 10.1569 3.23869 9.84309 3.43155 9.64824L8.42616 4.60245Z" />
|
<path d="M8.42616 4.60245C8.6193 4.40733 8.61898 4.09297 8.42545 3.89824L7.78047 3.24928C7.58466 3.05226 7.26578 3.05261 7.07041 3.25007L0.739669 9.64832C0.5469 9.84314 0.546901 10.1568 0.739669 10.3517L7.07041 16.7499C7.26578 16.9474 7.58465 16.9477 7.78047 16.7507L8.42545 16.1017C8.61898 15.907 8.6193 15.5927 8.42616 15.3975L3.43155 10.3517C3.23869 10.1569 3.23869 9.84309 3.43155 9.64824L8.42616 4.60245Z" />
|
||||||
</svg>;
|
</svg>;
|
||||||
@ -60,7 +58,19 @@ function cleanMessage(msg: Message) {
|
|||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openViewRawModal(json: string, type: string, msgContent?: string) {
|
function CodeBlock(props: { content: string, lang: string; }) {
|
||||||
|
return (
|
||||||
|
// make text selectable
|
||||||
|
<div style={{ userSelect: "text" }}>
|
||||||
|
{Parser.defaultRules.codeBlock.react(props, null, {})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openViewRawModal(msg: Message) {
|
||||||
|
msg = cleanMessage(msg);
|
||||||
|
const msgJson = JSON.stringify(msg, null, 4);
|
||||||
|
|
||||||
const key = openModal(props => (
|
const key = openModal(props => (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<ModalRoot {...props} size={ModalSize.LARGE}>
|
<ModalRoot {...props} size={ModalSize.LARGE}>
|
||||||
@ -70,28 +80,26 @@ function openViewRawModal(json: string, type: string, msgContent?: string) {
|
|||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<div style={{ padding: "16px 0" }}>
|
<div style={{ padding: "16px 0" }}>
|
||||||
{!!msgContent && (
|
{!!msg.content && (
|
||||||
<>
|
<>
|
||||||
<Forms.FormTitle tag="h5">Content</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">Content</Forms.FormTitle>
|
||||||
<CodeBlock content={msgContent} lang="" />
|
<CodeBlock content={msg.content} lang="" />
|
||||||
<Forms.FormDivider className={Margins.bottom20} />
|
<Forms.FormDivider className={Margins.bottom20} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Forms.FormTitle tag="h5">{type} Data</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">Message Data</Forms.FormTitle>
|
||||||
<CodeBlock content={json} lang="json" />
|
<CodeBlock content={msgJson} lang="json" />
|
||||||
</div>
|
</div>
|
||||||
</ModalContent >
|
</ModalContent >
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Flex cellSpacing={10}>
|
<Flex cellSpacing={10}>
|
||||||
<Button onClick={() => copyWithToast(json, `${type} data copied to clipboard!`)}>
|
<Button onClick={() => copyWithToast(msgJson, "Message data copied to clipboard!")}>
|
||||||
Copy {type} JSON
|
Copy Message JSON
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => copyWithToast(msg.content, "Content copied to clipboard!")}>
|
||||||
|
Copy Raw Content
|
||||||
</Button>
|
</Button>
|
||||||
{!!msgContent && (
|
|
||||||
<Button onClick={() => copyWithToast(msgContent, "Content copied to clipboard!")}>
|
|
||||||
Copy Raw Content
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</ModalRoot >
|
</ModalRoot >
|
||||||
@ -99,13 +107,6 @@ function openViewRawModal(json: string, type: string, msgContent?: string) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function openViewRawModalMessage(msg: Message) {
|
|
||||||
msg = cleanMessage(msg);
|
|
||||||
const msgJson = JSON.stringify(msg, null, 4);
|
|
||||||
|
|
||||||
return openViewRawModal(msgJson, "Message", msg.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
clickMethod: {
|
clickMethod: {
|
||||||
description: "Change the button to view the raw content/data of any message.",
|
description: "Change the button to view the raw content/data of any message.",
|
||||||
@ -117,34 +118,10 @@ const settings = definePluginSettings({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function MakeContextCallback(name: string) {
|
|
||||||
const callback: NavContextMenuPatchCallback = (children, props) => () => {
|
|
||||||
if (name === "Guild" && !props.guild) return;
|
|
||||||
const lastChild = children.at(-1);
|
|
||||||
if (lastChild?.key === "developer-actions") {
|
|
||||||
const p = lastChild.props;
|
|
||||||
if (!Array.isArray(p.children))
|
|
||||||
p.children = [p.children];
|
|
||||||
({ children } = p);
|
|
||||||
}
|
|
||||||
|
|
||||||
children.splice(-1, 0,
|
|
||||||
<Menu.MenuItem
|
|
||||||
id={`vc-view-${name.toLowerCase()}-raw`}
|
|
||||||
label="View Raw"
|
|
||||||
action={() => openViewRawModal(JSON.stringify(props[name.toLowerCase()], null, 4), name)}
|
|
||||||
icon={CopyIcon}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ViewRaw",
|
name: "ViewRaw",
|
||||||
description: "Copy and view the raw content/data of any message, channel or guild",
|
description: "Copy and view the raw content/data of any message.",
|
||||||
authors: [Devs.KingFish, Devs.Ven, Devs.rad, Devs.ImLvna],
|
authors: [Devs.KingFish, Devs.Ven, Devs.rad],
|
||||||
dependencies: ["MessagePopoverAPI"],
|
dependencies: ["MessagePopoverAPI"],
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
@ -154,7 +131,7 @@ export default definePlugin({
|
|||||||
if (settings.store.clickMethod === "Right") {
|
if (settings.store.clickMethod === "Right") {
|
||||||
copyWithToast(msg.content);
|
copyWithToast(msg.content);
|
||||||
} else {
|
} else {
|
||||||
openViewRawModalMessage(msg);
|
openViewRawModal(msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -166,7 +143,7 @@ export default definePlugin({
|
|||||||
} else {
|
} else {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
openViewRawModalMessage(msg);
|
openViewRawModal(msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,16 +160,9 @@ export default definePlugin({
|
|||||||
onContextMenu: handleContextMenu
|
onContextMenu: handleContextMenu
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
addContextMenuPatch("guild-context", MakeContextCallback("Guild"));
|
|
||||||
addContextMenuPatch("channel-context", MakeContextCallback("Channel"));
|
|
||||||
addContextMenuPatch("user-context", MakeContextCallback("User"));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
removeButton("CopyRawMessage");
|
removeButton("CopyRawMessage");
|
||||||
removeContextMenuPatch("guild-context", MakeContextCallback("Guild"));
|
|
||||||
removeContextMenuPatch("channel-context", MakeContextCallback("Channel"));
|
|
||||||
removeContextMenuPatch("user-context", MakeContextCallback("User"));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||||
|
import { Flex } from "@components/Flex";
|
||||||
import { Microphone } from "@components/Icons";
|
import { Microphone } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
|
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
|
||||||
@ -38,7 +39,6 @@ import { VoiceRecorderWeb } from "./WebRecorder";
|
|||||||
const CloudUpload = findLazy(m => m.prototype?.uploadFileToCloud);
|
const CloudUpload = findLazy(m => m.prototype?.uploadFileToCloud);
|
||||||
const MessageCreator = findByPropsLazy("getSendMessageOptionsForReply", "sendMessage");
|
const MessageCreator = findByPropsLazy("getSendMessageOptionsForReply", "sendMessage");
|
||||||
const PendingReplyStore = findStoreLazy("PendingReplyStore");
|
const PendingReplyStore = findStoreLazy("PendingReplyStore");
|
||||||
const OptionClasses = findByPropsLazy("optionName", "optionIcon", "optionLabel");
|
|
||||||
|
|
||||||
export type VoiceRecorder = ComponentType<{
|
export type VoiceRecorder = ComponentType<{
|
||||||
setAudioBlob(blob: Blob): void;
|
setAudioBlob(blob: Blob): void;
|
||||||
@ -226,10 +226,12 @@ const ctxMenuPatch: NavContextMenuPatchCallback = (children, props) => () => {
|
|||||||
<Menu.MenuItem
|
<Menu.MenuItem
|
||||||
id="vc-send-vmsg"
|
id="vc-send-vmsg"
|
||||||
label={
|
label={
|
||||||
<div className={OptionClasses.optionLabel}>
|
<>
|
||||||
<Microphone className={OptionClasses.optionIcon} height={24} width={24} />
|
<Flex flexDirection="row" style={{ alignItems: "center", gap: 8 }}>
|
||||||
<div className={OptionClasses.optionName}>Send voice message</div>
|
<Microphone height={24} width={24} />
|
||||||
</div>
|
Send voice message
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
action={() => openModal(modalProps => <Modal modalProps={modalProps} />)}
|
action={() => openModal(modalProps => <Modal modalProps={modalProps} />)}
|
||||||
/>
|
/>
|
||||||
|
@ -355,18 +355,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
|||||||
name: "bb010g",
|
name: "bb010g",
|
||||||
id: 72791153467990016n,
|
id: 72791153467990016n,
|
||||||
},
|
},
|
||||||
Lumap: {
|
|
||||||
name: "lumap",
|
|
||||||
id: 635383782576357407n
|
|
||||||
},
|
|
||||||
Dolfies: {
|
|
||||||
name: "Dolfies",
|
|
||||||
id: 852892297661906993n,
|
|
||||||
},
|
|
||||||
RuukuLada: {
|
RuukuLada: {
|
||||||
name: "RuukuLada",
|
name: "RuukuLada",
|
||||||
id: 119705748346241027n,
|
id: 119705748346241027n,
|
||||||
}
|
},
|
||||||
} satisfies Record<string, Dev>);
|
} satisfies Record<string, Dev>);
|
||||||
|
|
||||||
// iife so #__PURE__ works correctly
|
// iife so #__PURE__ works correctly
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
import { MessageObject } from "@api/MessageEvents";
|
import { MessageObject } from "@api/MessageEvents";
|
||||||
import { findByCodeLazy, findByPropsLazy, findLazy } from "@webpack";
|
import { findByCodeLazy, findByPropsLazy, findLazy } from "@webpack";
|
||||||
import { ChannelStore, ComponentDispatch, FluxDispatcher, GuildStore, MaskedLink, ModalImageClasses, PrivateChannelsStore, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileStore, UserUtils } from "@webpack/common";
|
import { ChannelStore, ComponentDispatch, GuildStore, MaskedLink, ModalImageClasses, PrivateChannelsStore, SelectedChannelStore, SelectedGuildStore, UserUtils } from "@webpack/common";
|
||||||
import { Guild, Message, User } from "discord-types/general";
|
import { Guild, Message, User } from "discord-types/general";
|
||||||
|
|
||||||
import { ImageModal, ModalRoot, ModalSize, openModal } from "./modal";
|
import { ImageModal, ModalRoot, ModalSize, openModal } from "./modal";
|
||||||
@ -118,41 +118,6 @@ export async function openUserProfile(id: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FetchUserProfileOptions {
|
|
||||||
friend_token?: string;
|
|
||||||
connections_role_id?: string;
|
|
||||||
guild_id?: string;
|
|
||||||
with_mutual_guilds?: boolean;
|
|
||||||
with_mutual_friends_count?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch a user's profile
|
|
||||||
*/
|
|
||||||
export async function fetchUserProfile(id: string, options?: FetchUserProfileOptions) {
|
|
||||||
const cached = UserProfileStore.getUserProfile(id);
|
|
||||||
if (cached) return cached;
|
|
||||||
|
|
||||||
FluxDispatcher.dispatch({ type: "USER_PROFILE_FETCH_START", userId: id });
|
|
||||||
|
|
||||||
const { body } = await RestAPI.get({
|
|
||||||
url: `/users/${id}/profile`,
|
|
||||||
query: {
|
|
||||||
with_mutual_guilds: false,
|
|
||||||
with_mutual_friends_count: false,
|
|
||||||
...options
|
|
||||||
},
|
|
||||||
oldFormErrors: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
FluxDispatcher.dispatch({ type: "USER_UPDATE", user: body.user });
|
|
||||||
await FluxDispatcher.dispatch({ type: "USER_PROFILE_FETCH_SUCCESS", ...body });
|
|
||||||
if (options?.guild_id && body.guild_member)
|
|
||||||
FluxDispatcher.dispatch({ type: "GUILD_MEMBER_PROFILE_UPDATE", guildId: options.guild_id, guildMember: body.guild_member });
|
|
||||||
|
|
||||||
return UserProfileStore.getUserProfile(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the unique username for a user. Returns user.username for pomelo people, user.tag otherwise
|
* Get the unique username for a user. Returns user.username for pomelo people, user.tag otherwise
|
||||||
*/
|
*/
|
||||||
|
@ -74,16 +74,6 @@ export function isObject(obj: unknown): obj is object {
|
|||||||
return typeof obj === "object" && obj !== null && !Array.isArray(obj);
|
return typeof obj === "object" && obj !== null && !Array.isArray(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an object is empty or in other words has no own properties
|
|
||||||
*/
|
|
||||||
export function isObjectEmpty(obj: object) {
|
|
||||||
for (const k in obj)
|
|
||||||
if (Object.hasOwn(obj, k)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns null if value is not a URL, otherwise return URL object.
|
* Returns null if value is not a URL, otherwise return URL object.
|
||||||
* Avoids having to wrap url checks in a try/catch
|
* Avoids having to wrap url checks in a try/catch
|
||||||
|
@ -48,7 +48,6 @@ export let PoggerModeSettingsStore: GenericStore;
|
|||||||
|
|
||||||
export let GuildStore: Stores.GuildStore & t.FluxStore;
|
export let GuildStore: Stores.GuildStore & t.FluxStore;
|
||||||
export let UserStore: Stores.UserStore & t.FluxStore;
|
export let UserStore: Stores.UserStore & t.FluxStore;
|
||||||
export let UserProfileStore: GenericStore;
|
|
||||||
export let SelectedChannelStore: Stores.SelectedChannelStore & t.FluxStore;
|
export let SelectedChannelStore: Stores.SelectedChannelStore & t.FluxStore;
|
||||||
export let SelectedGuildStore: t.FluxStore & Record<string, any>;
|
export let SelectedGuildStore: t.FluxStore & Record<string, any>;
|
||||||
export let ChannelStore: Stores.ChannelStore & t.FluxStore;
|
export let ChannelStore: Stores.ChannelStore & t.FluxStore;
|
||||||
@ -87,7 +86,6 @@ export const useStateFromStores: <T>(
|
|||||||
|
|
||||||
waitForStore("DraftStore", s => DraftStore = s);
|
waitForStore("DraftStore", s => DraftStore = s);
|
||||||
waitForStore("UserStore", s => UserStore = s);
|
waitForStore("UserStore", s => UserStore = s);
|
||||||
waitForStore("UserProfileStore", m => UserProfileStore = m);
|
|
||||||
waitForStore("ChannelStore", m => ChannelStore = m);
|
waitForStore("ChannelStore", m => ChannelStore = m);
|
||||||
waitForStore("SelectedChannelStore", m => SelectedChannelStore = m);
|
waitForStore("SelectedChannelStore", m => SelectedChannelStore = m);
|
||||||
waitForStore("SelectedGuildStore", m => SelectedGuildStore = m);
|
waitForStore("SelectedGuildStore", m => SelectedGuildStore = m);
|
||||||
|
16
src/webpack/common/types/components.d.ts
vendored
16
src/webpack/common/types/components.d.ts
vendored
@ -398,18 +398,12 @@ export type Paginator = ComponentType<{
|
|||||||
hideMaxPage?: boolean;
|
hideMaxPage?: boolean;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type MaskedLink = ComponentType<PropsWithChildren<{
|
export type MaskedLink = ComponentType<{
|
||||||
|
onClick(): void;
|
||||||
|
trusted: boolean;
|
||||||
|
title: string,
|
||||||
href: string;
|
href: string;
|
||||||
rel?: string;
|
}>;
|
||||||
target?: string;
|
|
||||||
title?: string,
|
|
||||||
className?: string;
|
|
||||||
tabIndex?: number;
|
|
||||||
onClick?(): void;
|
|
||||||
trusted?: boolean;
|
|
||||||
messageId?: string;
|
|
||||||
channelId?: string;
|
|
||||||
}>>;
|
|
||||||
|
|
||||||
export type ScrollerThin = ComponentType<PropsWithChildren<{
|
export type ScrollerThin = ComponentType<PropsWithChildren<{
|
||||||
className?: string;
|
className?: string;
|
||||||
|
Reference in New Issue
Block a user