Merge branch 'dev' into translation
This commit is contained in:
commit
b51d882940
96 changed files with 962 additions and 1310 deletions
23
.github/workflows/publish.yml
vendored
23
.github/workflows/publish.yml
vendored
|
|
@ -77,13 +77,22 @@ jobs:
|
||||||
if: steps.check.outputs.release == 'true'
|
if: steps.check.outputs.release == 'true'
|
||||||
run: pnpm buildWebStandalone
|
run: pnpm buildWebStandalone
|
||||||
|
|
||||||
|
- name: Create sources zip
|
||||||
|
if: steps.check.outputs.release == 'true'
|
||||||
|
run: zip -r dist/extension-sources.zip . -x "node_modules/*" -x "dist/*" -x ".git/*"
|
||||||
|
|
||||||
- name: Publish extension
|
- name: Publish extension
|
||||||
if: steps.check.outputs.release == 'true'
|
if: steps.check.outputs.release == 'true'
|
||||||
run: |
|
run: pnpx publish-browser-extension@latest --chrome-zip dist/extension-chrome.zip --firefox-zip dist/extension-firefox.zip --firefox-sources-zip dist/extension-sources.zip --edge-zip dist/extension-chrome.zip
|
||||||
cd dist/browser/chromium-unpacked
|
|
||||||
pnpx chrome-webstore-upload-cli@2.1.0 upload --auto-publish
|
|
||||||
env:
|
env:
|
||||||
EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }}
|
CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }}
|
||||||
CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }}
|
CHROME_CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }}
|
||||||
CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }}
|
CHROME_CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }}
|
||||||
REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }}
|
CHROME_REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }}
|
||||||
|
FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }}
|
||||||
|
FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER }}
|
||||||
|
FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET }}
|
||||||
|
EDGE_PRODUCT_ID: ${{ secrets.EDGE_PRODUCT_ID }}
|
||||||
|
EDGE_CLIENT_ID: ${{ secrets.EDGE_CLIENT_ID }}
|
||||||
|
EDGE_API_KEY: ${{ secrets.EDGE_API_KEY }}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "equicord",
|
"name": "equicord",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"version": "1.13.6.2",
|
"version": "1.13.6.4",
|
||||||
"description": "The other cutest Discord client mod",
|
"description": "The other cutest Discord client mod",
|
||||||
"homepage": "https://github.com/Equicord/Equicord#readme",
|
"homepage": "https://github.com/Equicord/Equicord#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@equicord/types",
|
"name": "@equicord/types",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.13.4",
|
"version": "1.13.6",
|
||||||
"description": "",
|
"description": "",
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
import globalBadges from "@equicordplugins/globalBadges";
|
||||||
import BadgeAPIPlugin from "@plugins/_api/badges";
|
import BadgeAPIPlugin from "@plugins/_api/badges";
|
||||||
import { ComponentType, HTMLProps } from "react";
|
import { ComponentType, HTMLProps } from "react";
|
||||||
|
|
||||||
|
import { isPluginEnabled } from "./PluginManager";
|
||||||
|
|
||||||
export const enum BadgePosition {
|
export const enum BadgePosition {
|
||||||
START,
|
START,
|
||||||
END
|
END
|
||||||
|
|
@ -99,6 +102,18 @@ export function _getBadges(args: BadgeUserArgs) {
|
||||||
|
|
||||||
const donorBadges = BadgeAPIPlugin.getDonorBadges(args.userId);
|
const donorBadges = BadgeAPIPlugin.getDonorBadges(args.userId);
|
||||||
const equicordDonorBadges = BadgeAPIPlugin.getEquicordDonorBadges(args.userId);
|
const equicordDonorBadges = BadgeAPIPlugin.getEquicordDonorBadges(args.userId);
|
||||||
|
const GlobalBadges = isPluginEnabled(globalBadges.name) ? globalBadges.getGlobalBadges(args.userId) : false;
|
||||||
|
|
||||||
|
// do globalbadges first so it shows before the contrib badges but after donor badges
|
||||||
|
if (GlobalBadges) {
|
||||||
|
badges.unshift(
|
||||||
|
...GlobalBadges.map(badge => ({
|
||||||
|
...args,
|
||||||
|
...badge,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (donorBadges) {
|
if (donorBadges) {
|
||||||
badges.unshift(
|
badges.unshift(
|
||||||
...donorBadges.map(badge => ({
|
...donorBadges.map(badge => ({
|
||||||
|
|
|
||||||
62
src/api/HeaderBar.tsx
Normal file
62
src/api/HeaderBar.tsx
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2025 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
import { useEffect, useState } from "@webpack/common";
|
||||||
|
import type { JSX } from "react";
|
||||||
|
|
||||||
|
export type HeaderBarButtonFactory = () => JSX.Element | null;
|
||||||
|
|
||||||
|
interface HeaderBarButton {
|
||||||
|
render: HeaderBarButtonFactory;
|
||||||
|
priority: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buttons = new Map<string, HeaderBarButton>();
|
||||||
|
|
||||||
|
const listeners = new Set<() => void>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a button to the header bar.
|
||||||
|
* @param id Unique identifier for the button.
|
||||||
|
* @param render Function that renders the button component.
|
||||||
|
* @param priority Higher priority = more to the right. Default is 0.
|
||||||
|
*/
|
||||||
|
export function addHeaderBarButton(id: string, render: HeaderBarButtonFactory, priority = 0) {
|
||||||
|
buttons.set(id, { render, priority });
|
||||||
|
listeners.forEach(l => l());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a button from the header bar.
|
||||||
|
* @param id The identifier of the button to remove.
|
||||||
|
*/
|
||||||
|
export function removeHeaderBarButton(id: string) {
|
||||||
|
buttons.delete(id);
|
||||||
|
listeners.forEach(l => l());
|
||||||
|
}
|
||||||
|
|
||||||
|
function HeaderBarButtons() {
|
||||||
|
const [, forceUpdate] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const listener = () => forceUpdate(n => n + 1);
|
||||||
|
listeners.add(listener);
|
||||||
|
return () => { listeners.delete(listener); };
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const sorted = Array.from(buttons).sort(([, a], [, b]) => a.priority - b.priority);
|
||||||
|
|
||||||
|
return sorted.map(([id, { render: Button }]) => (
|
||||||
|
<ErrorBoundary noop key={id}>
|
||||||
|
<Button />
|
||||||
|
</ErrorBoundary>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function _addButtons() {
|
||||||
|
return [<HeaderBarButtons key="vc-header-bar-buttons" />];
|
||||||
|
}
|
||||||
|
|
@ -40,6 +40,8 @@ import Plugins from "~plugins";
|
||||||
export { Plugins as plugins };
|
export { Plugins as plugins };
|
||||||
|
|
||||||
import { traceFunction } from "../debug/Tracer";
|
import { traceFunction } from "../debug/Tracer";
|
||||||
|
import { addAudioProcessor, removeAudioProcessor } from "./AudioPlayer";
|
||||||
|
import { addHeaderBarButton, removeHeaderBarButton } from "./HeaderBar";
|
||||||
|
|
||||||
const logger = new Logger("PluginManager", "#a6d189");
|
const logger = new Logger("PluginManager", "#a6d189");
|
||||||
|
|
||||||
|
|
@ -186,7 +188,9 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p:
|
||||||
const {
|
const {
|
||||||
name, commands, contextMenus, managedStyle, userProfileBadges,
|
name, commands, contextMenus, managedStyle, userProfileBadges,
|
||||||
onBeforeMessageEdit, onBeforeMessageSend, onMessageClick,
|
onBeforeMessageEdit, onBeforeMessageSend, onMessageClick,
|
||||||
renderChatBarButton, chatBarButton, renderMemberListDecorator, renderMessageAccessory, renderMessageDecoration, renderMessagePopoverButton, messagePopoverButton, renderNicknameIcon
|
renderChatBarButton, chatBarButton, renderMemberListDecorator, renderMessageAccessory, renderMessageDecoration, renderMessagePopoverButton, messagePopoverButton,
|
||||||
|
// Custom
|
||||||
|
renderNicknameIcon, renderHeaderBarButton, audioProcessor
|
||||||
} = p;
|
} = p;
|
||||||
|
|
||||||
if (p.start) {
|
if (p.start) {
|
||||||
|
|
@ -240,13 +244,17 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p:
|
||||||
// @ts-expect-error: legacy code doesn't have icon
|
// @ts-expect-error: legacy code doesn't have icon
|
||||||
else if (renderChatBarButton) addChatBarButton(name, renderChatBarButton);
|
else if (renderChatBarButton) addChatBarButton(name, renderChatBarButton);
|
||||||
if (renderMemberListDecorator) addMemberListDecorator(name, renderMemberListDecorator);
|
if (renderMemberListDecorator) addMemberListDecorator(name, renderMemberListDecorator);
|
||||||
if (renderNicknameIcon) addNicknameIcon(name, renderNicknameIcon);
|
|
||||||
if (renderMessageDecoration) addMessageDecoration(name, renderMessageDecoration);
|
if (renderMessageDecoration) addMessageDecoration(name, renderMessageDecoration);
|
||||||
if (renderMessageAccessory) addMessageAccessory(name, renderMessageAccessory);
|
if (renderMessageAccessory) addMessageAccessory(name, renderMessageAccessory);
|
||||||
if (messagePopoverButton) addMessagePopoverButton(name, messagePopoverButton.render, messagePopoverButton.icon);
|
if (messagePopoverButton) addMessagePopoverButton(name, messagePopoverButton.render, messagePopoverButton.icon);
|
||||||
// @ts-expect-error: legacy code doesn't have icon
|
// @ts-expect-error: legacy code doesn't have icon
|
||||||
else if (renderMessagePopoverButton) addMessagePopoverButton(name, renderMessagePopoverButton);
|
else if (renderMessagePopoverButton) addMessagePopoverButton(name, renderMessagePopoverButton);
|
||||||
|
|
||||||
|
// Custom
|
||||||
|
if (renderNicknameIcon) addNicknameIcon(name, renderNicknameIcon);
|
||||||
|
if (renderHeaderBarButton) addHeaderBarButton(name, renderHeaderBarButton);
|
||||||
|
if (audioProcessor) addAudioProcessor(name, audioProcessor);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, p => `startPlugin ${p.name}`);
|
}, p => `startPlugin ${p.name}`);
|
||||||
|
|
||||||
|
|
@ -254,7 +262,9 @@ export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plu
|
||||||
const {
|
const {
|
||||||
name, commands, contextMenus, managedStyle, userProfileBadges,
|
name, commands, contextMenus, managedStyle, userProfileBadges,
|
||||||
onBeforeMessageEdit, onBeforeMessageSend, onMessageClick,
|
onBeforeMessageEdit, onBeforeMessageSend, onMessageClick,
|
||||||
renderChatBarButton, chatBarButton, renderMemberListDecorator, renderMessageAccessory, renderMessageDecoration, renderMessagePopoverButton, messagePopoverButton, renderNicknameIcon
|
renderChatBarButton, chatBarButton, renderMemberListDecorator, renderMessageAccessory, renderMessageDecoration, renderMessagePopoverButton, messagePopoverButton,
|
||||||
|
// Custom
|
||||||
|
renderNicknameIcon, renderHeaderBarButton, audioProcessor
|
||||||
} = p;
|
} = p;
|
||||||
|
|
||||||
if (p.stop) {
|
if (p.stop) {
|
||||||
|
|
@ -304,11 +314,15 @@ export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plu
|
||||||
|
|
||||||
if (chatBarButton || renderChatBarButton) removeChatBarButton(name);
|
if (chatBarButton || renderChatBarButton) removeChatBarButton(name);
|
||||||
if (renderMemberListDecorator) removeMemberListDecorator(name);
|
if (renderMemberListDecorator) removeMemberListDecorator(name);
|
||||||
if (renderNicknameIcon) removeNicknameIcon(name);
|
|
||||||
if (renderMessageDecoration) removeMessageDecoration(name);
|
if (renderMessageDecoration) removeMessageDecoration(name);
|
||||||
if (renderMessageAccessory) removeMessageAccessory(name);
|
if (renderMessageAccessory) removeMessageAccessory(name);
|
||||||
if (messagePopoverButton || renderMessagePopoverButton) removeMessagePopoverButton(name);
|
if (messagePopoverButton || renderMessagePopoverButton) removeMessagePopoverButton(name);
|
||||||
|
|
||||||
|
// Custom
|
||||||
|
if (renderNicknameIcon) removeNicknameIcon(name);
|
||||||
|
if (renderHeaderBarButton) removeHeaderBarButton(name);
|
||||||
|
if (audioProcessor) removeAudioProcessor(name);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, p => `stopPlugin ${p.name}`);
|
}, p => `stopPlugin ${p.name}`);
|
||||||
|
|
||||||
|
|
@ -318,7 +332,9 @@ export const initPluginManager = onlyOnce(function init() {
|
||||||
|
|
||||||
const pluginKeysToBind: Array<keyof PluginDef & `${"on" | "render"}${string}`> = [
|
const pluginKeysToBind: Array<keyof PluginDef & `${"on" | "render"}${string}`> = [
|
||||||
"onBeforeMessageEdit", "onBeforeMessageSend", "onMessageClick",
|
"onBeforeMessageEdit", "onBeforeMessageSend", "onMessageClick",
|
||||||
"renderChatBarButton", "renderMemberListDecorator", "renderMessageAccessory", "renderMessageDecoration", "renderMessagePopoverButton", "renderNicknameIcon"
|
"renderChatBarButton", "renderMemberListDecorator", "renderMessageAccessory", "renderMessageDecoration", "renderMessagePopoverButton",
|
||||||
|
// Custom
|
||||||
|
"renderNicknameIcon", "renderHeaderBarButton"
|
||||||
];
|
];
|
||||||
|
|
||||||
const neededApiPlugins = new Set<string>();
|
const neededApiPlugins = new Set<string>();
|
||||||
|
|
@ -353,9 +369,13 @@ export const initPluginManager = onlyOnce(function init() {
|
||||||
if (p.renderMessageAccessory) neededApiPlugins.add("MessageAccessoriesAPI");
|
if (p.renderMessageAccessory) neededApiPlugins.add("MessageAccessoriesAPI");
|
||||||
if (p.renderMessageDecoration) neededApiPlugins.add("MessageDecorationsAPI");
|
if (p.renderMessageDecoration) neededApiPlugins.add("MessageDecorationsAPI");
|
||||||
if (p.messagePopoverButton || p.renderMessagePopoverButton) neededApiPlugins.add("MessagePopoverAPI");
|
if (p.messagePopoverButton || p.renderMessagePopoverButton) neededApiPlugins.add("MessagePopoverAPI");
|
||||||
if (p.renderNicknameIcon) neededApiPlugins.add("NicknameIconsAPI");
|
|
||||||
if (p.userProfileBadge) neededApiPlugins.add("BadgeAPI");
|
if (p.userProfileBadge) neededApiPlugins.add("BadgeAPI");
|
||||||
|
|
||||||
|
// Custom
|
||||||
|
if (p.renderNicknameIcon) neededApiPlugins.add("NicknameIconsAPI");
|
||||||
|
if (p.renderHeaderBarButton) neededApiPlugins.add("HeaderBarAPI");
|
||||||
|
if (p.audioProcessor) neededApiPlugins.add("AudioPlayerAPI");
|
||||||
|
|
||||||
for (const key of pluginKeysToBind) {
|
for (const key of pluginKeysToBind) {
|
||||||
p[key] &&= p[key].bind(p) as any;
|
p[key] &&= p[key].bind(p) as any;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import * as $ChatButtons from "./ChatButtons";
|
||||||
import * as $Commands from "./Commands";
|
import * as $Commands from "./Commands";
|
||||||
import * as $ContextMenu from "./ContextMenu";
|
import * as $ContextMenu from "./ContextMenu";
|
||||||
import * as $DataStore from "./DataStore";
|
import * as $DataStore from "./DataStore";
|
||||||
|
import * as $HeaderBar from "./HeaderBar";
|
||||||
import * as $MemberListDecorators from "./MemberListDecorators";
|
import * as $MemberListDecorators from "./MemberListDecorators";
|
||||||
import * as $MessageAccessories from "./MessageAccessories";
|
import * as $MessageAccessories from "./MessageAccessories";
|
||||||
import * as $MessageDecorations from "./MessageDecorations";
|
import * as $MessageDecorations from "./MessageDecorations";
|
||||||
|
|
@ -129,6 +130,11 @@ export const ContextMenu = $ContextMenu;
|
||||||
*/
|
*/
|
||||||
export const ChatButtons = $ChatButtons;
|
export const ChatButtons = $ChatButtons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An API allowing you to add buttons to the header bar.
|
||||||
|
*/
|
||||||
|
export const HeaderBar = $HeaderBar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An API allowing you to update and re-render messages.
|
* An API allowing you to update and re-render messages.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
59
src/components/Alert.tsx
Normal file
59
src/components/Alert.tsx
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2024 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { filters, mapMangledModuleLazy } from "@webpack";
|
||||||
|
import type { ComponentType, CSSProperties, ReactNode } from "react";
|
||||||
|
|
||||||
|
const { HelpMessage, HelpMessageTypes } = mapMangledModuleLazy('POSITIVE="positive', {
|
||||||
|
HelpMessageTypes: filters.byProps("POSITIVE", "WARNING", "INFO", "ERROR"),
|
||||||
|
HelpMessage: filters.byCode(".iconDiv")
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface AlertProps {
|
||||||
|
children: ReactNode;
|
||||||
|
className?: string;
|
||||||
|
style?: CSSProperties;
|
||||||
|
icon?: ComponentType<{ className?: string; color?: string; }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Warning({ children, className, style, icon }: AlertProps) {
|
||||||
|
return (
|
||||||
|
<HelpMessage messageType={HelpMessageTypes.WARNING} className={className} style={style} icon={icon}>
|
||||||
|
{children}
|
||||||
|
</HelpMessage>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Info({ children, className, style, icon }: AlertProps) {
|
||||||
|
return (
|
||||||
|
<HelpMessage messageType={HelpMessageTypes.INFO} className={className} style={style} icon={icon}>
|
||||||
|
{children}
|
||||||
|
</HelpMessage>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Error({ children, className, style, icon }: AlertProps) {
|
||||||
|
return (
|
||||||
|
<HelpMessage messageType={HelpMessageTypes.ERROR} className={className} style={style} icon={icon}>
|
||||||
|
{children}
|
||||||
|
</HelpMessage>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Positive({ children, className, style, icon }: AlertProps) {
|
||||||
|
return (
|
||||||
|
<HelpMessage messageType={HelpMessageTypes.POSITIVE} className={className} style={style} icon={icon}>
|
||||||
|
{children}
|
||||||
|
</HelpMessage>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Alert = {
|
||||||
|
Warning,
|
||||||
|
Info,
|
||||||
|
Error,
|
||||||
|
Positive
|
||||||
|
};
|
||||||
|
|
@ -21,6 +21,7 @@ import "./themesStyles.css";
|
||||||
import { isPluginEnabled } from "@api/PluginManager";
|
import { isPluginEnabled } from "@api/PluginManager";
|
||||||
import { Settings, useSettings } from "@api/Settings";
|
import { Settings, useSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { Card } from "@components/Card";
|
import { Card } from "@components/Card";
|
||||||
import { Divider } from "@components/Divider";
|
import { Divider } from "@components/Divider";
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
|
|
@ -44,7 +45,7 @@ import { usercssParse } from "@utils/themes/usercss";
|
||||||
import { t } from "@utils/translation";
|
import { t } from "@utils/translation";
|
||||||
import { getStylusWebStoreUrl } from "@utils/web";
|
import { getStylusWebStoreUrl } from "@utils/web";
|
||||||
import { findLazy } from "@webpack";
|
import { findLazy } from "@webpack";
|
||||||
import { Alerts, Button, React, showToast, TabBar, TextInput, Tooltip, useEffect, useMemo, useRef, useState } from "@webpack/common";
|
import { Alerts, React, showToast, TabBar, TextInput, Tooltip, useEffect, useMemo, useRef, useState } from "@webpack/common";
|
||||||
import type { ComponentType, Ref, SyntheticEvent } from "react";
|
import type { ComponentType, Ref, SyntheticEvent } from "react";
|
||||||
import type { UserstyleHeader } from "usercss-meta";
|
import type { UserstyleHeader } from "usercss-meta";
|
||||||
|
|
||||||
|
|
@ -600,7 +601,7 @@ export function CspErrorCard() {
|
||||||
{i !== 0 && <Divider className={Margins.bottom8} />}
|
{i !== 0 && <Divider className={Margins.bottom8} />}
|
||||||
<div className="vc-settings-csp-row">
|
<div className="vc-settings-csp-row">
|
||||||
<Link href={url}>{url}</Link>
|
<Link href={url}>{url}</Link>
|
||||||
<Button color={Button.Colors.PRIMARY} onClick={() => allowUrl(url)} disabled={isImgurHtmlDomain(url)}>
|
<Button variant="secondary" onClick={() => allowUrl(url)} disabled={isImgurHtmlDomain(url)}>
|
||||||
Allow
|
Allow
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,8 @@ function ResetButton({ themeSettings, themeId, close, onReset }: ResetButtonProp
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
|
|
||||||
onClick={async () => {
|
onClick={() => {
|
||||||
await close(); // close the modal first to stop rendering
|
close(); // close the modal first to stop rendering
|
||||||
delete themeSettings[themeId];
|
delete themeSettings[themeId];
|
||||||
onReset();
|
onReset();
|
||||||
}}>
|
}}>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export * from "./Alert";
|
||||||
export * from "./BaseText";
|
export * from "./BaseText";
|
||||||
export * from "./Button";
|
export * from "./Button";
|
||||||
export * from "./Card";
|
export * from "./Card";
|
||||||
|
|
|
||||||
|
|
@ -16,23 +16,24 @@
|
||||||
* 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 { Button } from "@components/Button";
|
||||||
import { Heart } from "@components/Heart";
|
import { Heart } from "@components/Heart";
|
||||||
import { openInviteModal } from "@utils/discord";
|
import { openInviteModal } from "@utils/discord";
|
||||||
import { t } from "@utils/translation";
|
import { t } from "@utils/translation";
|
||||||
import { ButtonProps } from "@vencord/discord-types";
|
import { ButtonProps } from "@vencord/discord-types";
|
||||||
import { Button, showToast } from "@webpack/common";
|
import { showToast } from "@webpack/common";
|
||||||
|
|
||||||
export function DonateButton({
|
export function DonateButton({
|
||||||
look = Button.Looks.LINK,
|
equicord = false,
|
||||||
color = Button.Colors.TRANSPARENT,
|
|
||||||
link,
|
|
||||||
...props
|
...props
|
||||||
}: Partial<ButtonProps> & { link: string; }) {
|
}: Partial<ButtonProps> & { equicord?: boolean; }) {
|
||||||
|
const link = equicord ? "https://github.com/sponsors/thororen1234" : "https://github.com/sponsors/Vendicated";
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
{...props}
|
{...props}
|
||||||
look={look}
|
variant="none"
|
||||||
color={color}
|
size="medium"
|
||||||
|
type="button"
|
||||||
onClick={() => VencordNative.native.openExternal(link)}
|
onClick={() => VencordNative.native.openExternal(link)}
|
||||||
className="vc-donate-button"
|
className="vc-donate-button"
|
||||||
>
|
>
|
||||||
|
|
@ -43,15 +44,14 @@ export function DonateButton({
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InviteButton({
|
export function InviteButton({
|
||||||
look = Button.Looks.LINK,
|
|
||||||
color = Button.Colors.TRANSPARENT,
|
|
||||||
...props
|
...props
|
||||||
}: Partial<ButtonProps>) {
|
}: Partial<ButtonProps>) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
{...props}
|
{...props}
|
||||||
look={look}
|
variant="none"
|
||||||
color={color}
|
size="medium"
|
||||||
|
type="button"
|
||||||
onClick={async e => {
|
onClick={async e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
openInviteModal("equicord-1173279886065029291").catch(() =>
|
openInviteModal("equicord-1173279886065029291").catch(() =>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.vc-donate-button {
|
.vc-donate-button {
|
||||||
overflow: visible !important;
|
overflow: visible !important;
|
||||||
|
color: var(--text-default)
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-donate-button .vc-heart-icon {
|
.vc-donate-button .vc-heart-icon {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { Card } from "@components/Card";
|
import { Card } from "@components/Card";
|
||||||
import { Heading } from "@components/Heading";
|
import { Heading } from "@components/Heading";
|
||||||
import { Paragraph } from "@components/Paragraph";
|
import { Paragraph } from "@components/Paragraph";
|
||||||
|
|
@ -14,7 +15,7 @@ import { ChangeList } from "@utils/ChangeList";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { useForceUpdater } from "@utils/react";
|
import { useForceUpdater } from "@utils/react";
|
||||||
import { t } from "@utils/translation";
|
import { t } from "@utils/translation";
|
||||||
import { Button, React, Tooltip } from "@webpack/common";
|
import { React, Tooltip } from "@webpack/common";
|
||||||
|
|
||||||
import Plugins from "~plugins";
|
import Plugins from "~plugins";
|
||||||
|
|
||||||
|
|
@ -166,8 +167,8 @@ export function NewPluginsSection({
|
||||||
{tooltipProps => (
|
{tooltipProps => (
|
||||||
<Button
|
<Button
|
||||||
{...tooltipProps}
|
{...tooltipProps}
|
||||||
color={Button.Colors.LINK}
|
variant="link"
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
onClick={() => location.reload()}
|
onClick={() => location.reload()}
|
||||||
className={Margins.top16}
|
className={Margins.top16}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { Card } from "@components/Card";
|
import { Card } from "@components/Card";
|
||||||
import { Divider } from "@components/Divider";
|
import { Divider } from "@components/Divider";
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
|
|
@ -20,7 +21,7 @@ import { Margins } from "@utils/margins";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { t } from "@utils/translation";
|
import { t } from "@utils/translation";
|
||||||
import { getRepo, UpdateLogger } from "@utils/updater";
|
import { getRepo, UpdateLogger } from "@utils/updater";
|
||||||
import { Alerts, Button, React, Toasts } from "@webpack/common";
|
import { Alerts, React, Toasts } from "@webpack/common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChangelogEntry,
|
ChangelogEntry,
|
||||||
|
|
@ -116,9 +117,8 @@ function UpdateLogCard({
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.NONE}
|
size="min"
|
||||||
color={Button.Colors.TRANSPARENT}
|
variant="secondary"
|
||||||
look={Button.Looks.FILLED}
|
|
||||||
className="vc-changelog-delete-button"
|
className="vc-changelog-delete-button"
|
||||||
style={{
|
style={{
|
||||||
padding: "4px",
|
padding: "4px",
|
||||||
|
|
@ -500,14 +500,10 @@ function ChangelogContent() {
|
||||||
|
|
||||||
<div className="vc-changelog-controls">
|
<div className="vc-changelog-controls">
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
disabled={isLoading || repoPending || !!repoErr}
|
disabled={isLoading || repoPending || !!repoErr}
|
||||||
onClick={fetchChangelog}
|
onClick={fetchChangelog}
|
||||||
color={
|
variant={recentlyChecked ? "positive" : "primary"}
|
||||||
recentlyChecked
|
|
||||||
? Button.Colors.GREEN
|
|
||||||
: Button.Colors.BRAND
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{isLoading
|
{isLoading
|
||||||
? t("vencord.loading")
|
? t("vencord.loading")
|
||||||
|
|
@ -520,20 +516,16 @@ function ChangelogContent() {
|
||||||
{changelogHistory.length > 0 && (
|
{changelogHistory.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
color={
|
variant={showHistory ? "primary" : "secondary"}
|
||||||
showHistory
|
|
||||||
? Button.Colors.PRIMARY
|
|
||||||
: Button.Colors.BRAND
|
|
||||||
}
|
|
||||||
onClick={() => setShowHistory(!showHistory)}
|
onClick={() => setShowHistory(!showHistory)}
|
||||||
style={{ marginLeft: "8px" }}
|
style={{ marginLeft: "8px" }}
|
||||||
>
|
>
|
||||||
{showHistory ? t("vencord.logs.hideLogs") : t("vencord.logs.showLogs")}
|
{showHistory ? t("vencord.logs.hideLogs") : t("vencord.logs.showLogs")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
color={Button.Colors.RED}
|
variant="dangerPrimary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Alerts.show({
|
Alerts.show({
|
||||||
title: t("vencord.logs.clearAllLogs"),
|
title: t("vencord.logs.clearAllLogs"),
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import { generateId } from "@api/Commands";
|
||||||
import { Settings, useSettings } from "@api/Settings";
|
import { Settings, useSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
import { BaseText } from "@components/BaseText";
|
import { BaseText } from "@components/BaseText";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { Paragraph } from "@components/Paragraph";
|
import { Paragraph } from "@components/Paragraph";
|
||||||
|
|
@ -35,7 +36,7 @@ import { t } from "@utils/translation";
|
||||||
import { OptionType, Plugin } from "@utils/types";
|
import { OptionType, Plugin } from "@utils/types";
|
||||||
import { User } from "@vencord/discord-types";
|
import { User } from "@vencord/discord-types";
|
||||||
import { findByPropsLazy } from "@webpack";
|
import { findByPropsLazy } from "@webpack";
|
||||||
import { Button, Clickable, FluxDispatcher, React, Toasts, Tooltip, useEffect, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common";
|
import { Clickable, FluxDispatcher, React, Toasts, Tooltip, useEffect, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common";
|
||||||
import { Constructor } from "type-fest";
|
import { Constructor } from "type-fest";
|
||||||
|
|
||||||
import { PluginMeta } from "~plugins";
|
import { PluginMeta } from "~plugins";
|
||||||
|
|
@ -230,8 +231,8 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
{({ onMouseEnter, onMouseLeave }) => (
|
{({ onMouseEnter, onMouseLeave }) => (
|
||||||
<Button
|
<Button
|
||||||
className={cl("disable-warning")}
|
className={cl("disable-warning")}
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
color={Button.Colors.BRAND}
|
variant="primary"
|
||||||
onClick={handleResetClick}
|
onClick={handleResetClick}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
|
|
@ -352,16 +353,15 @@ export function openWarningModal(plugin?: Plugin | null, pluginModalProps?: Moda
|
||||||
<Flex className="vc-button-container">
|
<Flex className="vc-button-container">
|
||||||
<Flex className="button-group">
|
<Flex className="button-group">
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
color={Button.Colors.PRIMARY}
|
variant="secondary"
|
||||||
onClick={warningModalProps.onClose}
|
onClick={warningModalProps.onClose}
|
||||||
look={Button.Looks.FILLED}
|
|
||||||
>
|
>
|
||||||
{t("vencord.cancel")}
|
{t("vencord.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
{!Settings.ignoreResetWarning && (
|
{!Settings.ignoreResetWarning && (
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
className={cl("disable-warning")}
|
className={cl("disable-warning")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Settings.ignoreResetWarning = true;
|
Settings.ignoreResetWarning = true;
|
||||||
|
|
@ -371,7 +371,7 @@ export function openWarningModal(plugin?: Plugin | null, pluginModalProps?: Moda
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isPlugin) {
|
if (isPlugin) {
|
||||||
if (plugin && pluginModalProps)
|
if (plugin && pluginModalProps)
|
||||||
|
|
|
||||||
|
|
@ -17,66 +17,65 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { downloadSettingsBackup, uploadSettingsBackup } from "@api/SettingsSync/offline";
|
import { downloadSettingsBackup, uploadSettingsBackup } from "@api/SettingsSync/offline";
|
||||||
import { Card } from "@components/Card";
|
import { Alert } from "@components/Alert";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { Heading } from "@components/Heading";
|
import { Heading } from "@components/Heading";
|
||||||
import { Paragraph } from "@components/Paragraph";
|
import { Paragraph } from "@components/Paragraph";
|
||||||
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { Button, Text } from "@webpack/common";
|
|
||||||
|
|
||||||
function BackupAndRestoreTab() {
|
function BackupAndRestoreTab() {
|
||||||
return (
|
return (
|
||||||
<SettingsTab title="Backup & Restore">
|
<SettingsTab title="Backup & Restore">
|
||||||
<Flex flexDirection="column" gap="0.5em">
|
<Flex flexDirection="column" gap="0.5em">
|
||||||
<Card variant="warning">
|
<Alert.Warning>
|
||||||
<Heading tag="h4">Warning</Heading>
|
Importing a settings file will overwrite your current settings.
|
||||||
<Paragraph>Importing a settings file will overwrite your current settings.</Paragraph>
|
</Alert.Warning>
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Text variant="text-md/normal" className={Margins.bottom8}>
|
<Paragraph className={Margins.bottom8}>
|
||||||
You can import and export your Vencord settings as a JSON file.
|
You can import and export your Vencord settings as a JSON file.
|
||||||
This allows you to easily transfer your settings to another device,
|
This allows you to easily transfer your settings to another device,
|
||||||
or recover your settings after reinstalling Vencord or Discord.
|
or recover your settings after reinstalling Vencord or Discord.
|
||||||
</Text>
|
</Paragraph>
|
||||||
|
|
||||||
<Heading tag="h4">Settings Export contains:</Heading>
|
<Heading tag="h4">Settings Export contains:</Heading>
|
||||||
<Text variant="text-md/normal" className={Margins.bottom8}>
|
<Paragraph className={Margins.bottom8}>
|
||||||
<ul>
|
<ul>
|
||||||
<li>— Custom QuickCSS</li>
|
<li>— Custom QuickCSS</li>
|
||||||
<li>— Theme Links</li>
|
<li>— Theme Links</li>
|
||||||
<li>— Plugin Settings</li>
|
<li>— Plugin Settings</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Text>
|
</Paragraph>
|
||||||
|
|
||||||
<Flex>
|
<Flex>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => uploadSettingsBackup()}
|
onClick={() => uploadSettingsBackup()}
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
>
|
>
|
||||||
Import Settings
|
Import Settings
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => downloadSettingsBackup("settings")}
|
onClick={() => downloadSettingsBackup("settings")}
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
>
|
>
|
||||||
Export Settings
|
Export Settings
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => downloadSettingsBackup("plugins")}
|
onClick={() => downloadSettingsBackup("plugins")}
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
>
|
>
|
||||||
Export Plugins
|
Export Plugins
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => downloadSettingsBackup("css")}
|
onClick={() => downloadSettingsBackup("css")}
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
>
|
>
|
||||||
Export CSS
|
Export CSS
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => downloadSettingsBackup("datastore")}
|
onClick={() => downloadSettingsBackup("datastore")}
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
>
|
>
|
||||||
Export DataStores
|
Export DataStores
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
import { authorizeCloud, deauthorizeCloud } from "@api/SettingsSync/cloudSetup";
|
import { authorizeCloud, deauthorizeCloud } from "@api/SettingsSync/cloudSetup";
|
||||||
import { deleteCloudSettings, eraseAllCloudData, getCloudSettings, putCloudSettings } from "@api/SettingsSync/cloudSync";
|
import { deleteCloudSettings, eraseAllCloudData, getCloudSettings, putCloudSettings } from "@api/SettingsSync/cloudSync";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||||
import { Divider } from "@components/Divider";
|
import { Divider } from "@components/Divider";
|
||||||
import { FormSwitch } from "@components/FormSwitch";
|
import { FormSwitch } from "@components/FormSwitch";
|
||||||
|
|
@ -28,7 +29,7 @@ import { Link } from "@components/Link";
|
||||||
import { Paragraph } from "@components/Paragraph";
|
import { Paragraph } from "@components/Paragraph";
|
||||||
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { Alerts, Button, Tooltip, useState } from "@webpack/common";
|
import { Alerts, Tooltip, useState } from "@webpack/common";
|
||||||
|
|
||||||
function validateUrl(url: string) {
|
function validateUrl(url: string) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -60,7 +61,7 @@ function SettingsSyncSection() {
|
||||||
/>
|
/>
|
||||||
<div className="vc-cloud-settings-sync-grid">
|
<div className="vc-cloud-settings-sync-grid">
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
disabled={!sectionEnabled}
|
disabled={!sectionEnabled}
|
||||||
onClick={() => putCloudSettings(true)}
|
onClick={() => putCloudSettings(true)}
|
||||||
>
|
>
|
||||||
|
|
@ -71,8 +72,8 @@ function SettingsSyncSection() {
|
||||||
<Button
|
<Button
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
color={Button.Colors.RED}
|
variant="dangerPrimary"
|
||||||
disabled={!sectionEnabled}
|
disabled={!sectionEnabled}
|
||||||
onClick={() => getCloudSettings(true, true)}
|
onClick={() => getCloudSettings(true, true)}
|
||||||
>
|
>
|
||||||
|
|
@ -81,8 +82,8 @@ function SettingsSyncSection() {
|
||||||
)}
|
)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
color={Button.Colors.RED}
|
variant="dangerPrimary"
|
||||||
disabled={!sectionEnabled}
|
disabled={!sectionEnabled}
|
||||||
onClick={() => deleteCloudSettings()}
|
onClick={() => deleteCloudSettings()}
|
||||||
>
|
>
|
||||||
|
|
@ -152,7 +153,7 @@ function CloudTab() {
|
||||||
|
|
||||||
<Grid columns={2} gap="1em" className={Margins.top8}>
|
<Grid columns={2} gap="1em" className={Margins.top8}>
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.MEDIUM}
|
size="medium"
|
||||||
disabled={!settings.cloud.authenticated}
|
disabled={!settings.cloud.authenticated}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
settings.cloud.authenticated = false;
|
settings.cloud.authenticated = false;
|
||||||
|
|
@ -163,8 +164,8 @@ function CloudTab() {
|
||||||
Reauthorize
|
Reauthorize
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.MEDIUM}
|
size="medium"
|
||||||
color={Button.Colors.RED}
|
variant="dangerPrimary"
|
||||||
disabled={!settings.cloud.authenticated}
|
disabled={!settings.cloud.authenticated}
|
||||||
onClick={() => Alerts.show({
|
onClick={() => Alerts.show({
|
||||||
title: "Are you sure?",
|
title: "Are you sure?",
|
||||||
|
|
@ -177,10 +178,10 @@ function CloudTab() {
|
||||||
>
|
>
|
||||||
Erase All Data
|
Erase All Data
|
||||||
</Button>
|
</Button>
|
||||||
<Button size={Button.Sizes.MEDIUM} onClick={() => changeUrl("https://cloud.equicord.org/")}>
|
<Button size="medium" onClick={() => changeUrl("https://cloud.equicord.org/")}>
|
||||||
Use Equicord's Cloud
|
Use Equicord's Cloud
|
||||||
</Button>
|
</Button>
|
||||||
<Button size={Button.Sizes.MEDIUM} onClick={() => changeUrl("https://api.vencord.dev/")}>
|
<Button size="medium" onClick={() => changeUrl("https://api.vencord.dev/")}>
|
||||||
Use Vencord's Cloud
|
Use Vencord's Cloud
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { Card } from "@components/Card";
|
import { Card } from "@components/Card";
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
|
|
@ -13,7 +14,7 @@ import { Margins } from "@utils/margins";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { relaunch } from "@utils/native";
|
import { relaunch } from "@utils/native";
|
||||||
import { changes, checkForUpdates, update, updateError } from "@utils/updater";
|
import { changes, checkForUpdates, update, updateError } from "@utils/updater";
|
||||||
import { Alerts, Button, React, Toasts, useState } from "@webpack/common";
|
import { Alerts, React, Toasts, useState } from "@webpack/common";
|
||||||
|
|
||||||
import { runWithDispatch } from "./runWithDispatch";
|
import { runWithDispatch } from "./runWithDispatch";
|
||||||
|
|
||||||
|
|
@ -95,7 +96,7 @@ export function Updatable(props: CommonProps) {
|
||||||
<Flex className={classes(Margins.bottom8, Margins.top8)}>
|
<Flex className={classes(Margins.bottom8, Margins.top8)}>
|
||||||
{isOutdated && (
|
{isOutdated && (
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
disabled={isUpdating || isChecking}
|
disabled={isUpdating || isChecking}
|
||||||
onClick={runWithDispatch(setIsUpdating, async () => {
|
onClick={runWithDispatch(setIsUpdating, async () => {
|
||||||
if (await update()) {
|
if (await update()) {
|
||||||
|
|
@ -121,7 +122,7 @@ export function Updatable(props: CommonProps) {
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
disabled={isUpdating || isChecking}
|
disabled={isUpdating || isChecking}
|
||||||
onClick={runWithDispatch(setIsChecking, async () => {
|
onClick={runWithDispatch(setIsChecking, async () => {
|
||||||
const outdated = await checkForUpdates();
|
const outdated = await checkForUpdates();
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { Divider } from "@components/Divider";
|
import { Divider } from "@components/Divider";
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
|
|
@ -31,7 +32,7 @@ import { relaunch } from "@utils/native";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { t } from "@utils/translation";
|
import { t } from "@utils/translation";
|
||||||
import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater";
|
import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater";
|
||||||
import { Alerts, Button, Parser, React, Toasts } from "@webpack/common";
|
import { Alerts, Parser, React, Toasts } from "@webpack/common";
|
||||||
|
|
||||||
import gitHash from "~git-hash";
|
import gitHash from "~git-hash";
|
||||||
|
|
||||||
|
|
@ -92,7 +93,7 @@ function Updatable(props: CommonProps) {
|
||||||
<>
|
<>
|
||||||
<Flex className={classes(Margins.bottom8, Margins.top8)}>
|
<Flex className={classes(Margins.bottom8, Margins.top8)}>
|
||||||
{isOutdated && <Button
|
{isOutdated && <Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
disabled={isUpdating || isChecking}
|
disabled={isUpdating || isChecking}
|
||||||
onClick={withDispatcher(setIsUpdating, async () => {
|
onClick={withDispatcher(setIsUpdating, async () => {
|
||||||
if (await update()) {
|
if (await update()) {
|
||||||
|
|
@ -116,7 +117,7 @@ function Updatable(props: CommonProps) {
|
||||||
Update Now
|
Update Now
|
||||||
</Button>}
|
</Button>}
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size="small"
|
||||||
disabled={isUpdating || isChecking}
|
disabled={isUpdating || isChecking}
|
||||||
onClick={withDispatcher(setIsChecking, async () => {
|
onClick={withDispatcher(setIsChecking, async () => {
|
||||||
const outdated = await checkForUpdates();
|
const outdated = await checkForUpdates();
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
import { DonateButton } from "@components/settings/DonateButton";
|
import { DonateButton } from "@components/settings/DonateButton";
|
||||||
import BadgeAPI from "@plugins/_api/badges";
|
import BadgeAPI from "@plugins/_api/badges";
|
||||||
import { DONOR_ROLE_ID, VC_GUILD_ID } from "@utils/constants";
|
import { DONOR_ROLE_ID, VC_GUILD_ID } from "@utils/constants";
|
||||||
import { Button, GuildMemberStore } from "@webpack/common";
|
import { GuildMemberStore } from "@webpack/common";
|
||||||
|
|
||||||
export const isDonor = (userId: string) => !!(
|
export const isDonor = (userId: string) => !!(
|
||||||
BadgeAPI.getDonorBadges(userId)?.length > 0
|
BadgeAPI.getDonorBadges(userId)?.length > 0
|
||||||
|
|
@ -17,8 +17,6 @@ export const isDonor = (userId: string) => !!(
|
||||||
export function DonateButtonComponent() {
|
export function DonateButtonComponent() {
|
||||||
return (
|
return (
|
||||||
<DonateButton
|
<DonateButton
|
||||||
look={Button.Looks.FILLED}
|
|
||||||
color={Button.Colors.WHITE}
|
|
||||||
style={{ marginTop: "1em" }}
|
style={{ marginTop: "1em" }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
import { BaseText } from "@components/BaseText";
|
import { BaseText } from "@components/BaseText";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { FormSwitch } from "@components/FormSwitch";
|
import { FormSwitch } from "@components/FormSwitch";
|
||||||
|
|
@ -16,7 +17,7 @@ import { Margins } from "@utils/margins";
|
||||||
import { identity } from "@utils/misc";
|
import { identity } from "@utils/misc";
|
||||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { ModalCloseButton, ModalContent, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { t } from "@utils/translation";
|
import { t } from "@utils/translation";
|
||||||
import { Button, Select, Slider } from "@webpack/common";
|
import { Select, Slider } from "@webpack/common";
|
||||||
|
|
||||||
export function NotificationSection() {
|
export function NotificationSection() {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -47,3 +47,8 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vc-vencord-tab-settings-link {
|
||||||
|
color: var(--text-link);
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,9 @@ import "./VencordTab.css";
|
||||||
|
|
||||||
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
|
import { classNameFactory } from "@api/Styles";
|
||||||
|
import { Alert } from "@components/Alert";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
import { Divider } from "@components/Divider";
|
import { Divider } from "@components/Divider";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { FormSwitch } from "@components/FormSwitch";
|
import { FormSwitch } from "@components/FormSwitch";
|
||||||
|
|
@ -18,12 +21,12 @@ import { DonateButton, InviteButton, openContributorModal, openPluginModal, Sett
|
||||||
import { QuickAction, QuickActionCard } from "@components/settings/QuickAction";
|
import { QuickAction, QuickActionCard } from "@components/settings/QuickAction";
|
||||||
import { SpecialCard } from "@components/settings/SpecialCard";
|
import { SpecialCard } from "@components/settings/SpecialCard";
|
||||||
import { gitRemote } from "@shared/vencordUserAgent";
|
import { gitRemote } from "@shared/vencordUserAgent";
|
||||||
import { DONOR_ROLE_ID, GUILD_ID, VC_DONOR_ROLE_ID, VC_GUILD_ID } from "@utils/constants";
|
import { DONOR_ROLE_ID, GUILD_ID, IS_MAC, IS_WINDOWS, VC_DONOR_ROLE_ID, VC_GUILD_ID } from "@utils/constants";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { identity, isAnyPluginDev } from "@utils/misc";
|
import { identity, isAnyPluginDev } from "@utils/misc";
|
||||||
import { relaunch } from "@utils/native";
|
import { relaunch } from "@utils/native";
|
||||||
import { t, Translate } from "@utils/translation";
|
import { t, Translate } from "@utils/translation";
|
||||||
import { Button, GuildMemberStore, React, Select, UserStore } from "@webpack/common";
|
import { GuildMemberStore, React, Select, UserStore } from "@webpack/common";
|
||||||
import BadgeAPI from "plugins/_api/badges";
|
import BadgeAPI from "plugins/_api/badges";
|
||||||
|
|
||||||
import { openNotificationSettingsModal } from "./NotificationSettings";
|
import { openNotificationSettingsModal } from "./NotificationSettings";
|
||||||
|
|
@ -37,6 +40,8 @@ const COZY_CONTRIB_IMAGE = "https://cdn.discordapp.com/emojis/102653307095587233
|
||||||
const DONOR_BACKGROUND_IMAGE = "https://media.discordapp.net/stickers/1311070116305436712.png?size=2048";
|
const DONOR_BACKGROUND_IMAGE = "https://media.discordapp.net/stickers/1311070116305436712.png?size=2048";
|
||||||
const CONTRIB_BACKGROUND_IMAGE = "https://media.discordapp.net/stickers/1311070166481895484.png?size=2048";
|
const CONTRIB_BACKGROUND_IMAGE = "https://media.discordapp.net/stickers/1311070166481895484.png?size=2048";
|
||||||
|
|
||||||
|
const cl = classNameFactory("vc-vencord-tab-");
|
||||||
|
|
||||||
type KeysOfType<Object, Type> = {
|
type KeysOfType<Object, Type> = {
|
||||||
[K in keyof Object]: Object[K] extends Type ? K : never;
|
[K in keyof Object]: Object[K] extends Type ? K : never;
|
||||||
}[keyof Object];
|
}[keyof Object];
|
||||||
|
|
@ -49,9 +54,7 @@ function EquicordSettings() {
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const isWindows = navigator.platform.toLowerCase().startsWith("win");
|
const needsVibrancySettings = IS_DISCORD_DESKTOP && IS_MAC;
|
||||||
const isMac = navigator.platform.toLowerCase().startsWith("mac");
|
|
||||||
const needsVibrancySettings = IS_DISCORD_DESKTOP && isMac;
|
|
||||||
|
|
||||||
const user = UserStore?.getCurrentUser();
|
const user = UserStore?.getCurrentUser();
|
||||||
|
|
||||||
|
|
@ -77,7 +80,7 @@ function EquicordSettings() {
|
||||||
warning: { enabled: false },
|
warning: { enabled: false },
|
||||||
},
|
},
|
||||||
!IS_WEB &&
|
!IS_WEB &&
|
||||||
(!IS_DISCORD_DESKTOP || !isWindows
|
(!IS_DISCORD_DESKTOP || !IS_WINDOWS
|
||||||
? {
|
? {
|
||||||
key: "frameless",
|
key: "frameless",
|
||||||
title: t("vencord.settings.frameless.title"),
|
title: t("vencord.settings.frameless.title"),
|
||||||
|
|
@ -96,7 +99,7 @@ function EquicordSettings() {
|
||||||
description: t("vencord.settings.transparent.description"),
|
description: t("vencord.settings.transparent.description"),
|
||||||
restartRequired: true,
|
restartRequired: true,
|
||||||
warning: {
|
warning: {
|
||||||
enabled: isWindows,
|
enabled: IS_WINDOWS,
|
||||||
message: "Enabling this will prevent you from snapping this window.",
|
message: "Enabling this will prevent you from snapping this window.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -107,7 +110,7 @@ function EquicordSettings() {
|
||||||
warning: { enabled: false },
|
warning: { enabled: false },
|
||||||
},
|
},
|
||||||
!IS_WEB &&
|
!IS_WEB &&
|
||||||
isWindows && {
|
IS_WINDOWS && {
|
||||||
key: "winCtrlQ",
|
key: "winCtrlQ",
|
||||||
title: t("vencord.settings.winCtrlQ.title"),
|
title: t("vencord.settings.winCtrlQ.title"),
|
||||||
restartRequired: true,
|
restartRequired: true,
|
||||||
|
|
@ -206,8 +209,9 @@ function EquicordSettings() {
|
||||||
<Translate i18nKey="vencord.settings.hint">
|
<Translate i18nKey="vencord.settings.hint">
|
||||||
Hint: You can change the position of this settings section in the
|
Hint: You can change the position of this settings section in the
|
||||||
<Button
|
<Button
|
||||||
look={Button.Looks.LINK}
|
variant="none"
|
||||||
style={{ color: "var(--text-link)", display: "inline-block" }}
|
size="small"
|
||||||
|
className={cl("settings-link")}
|
||||||
onClick={() => openPluginModal(Vencord.Plugins.plugins.Settings)}
|
onClick={() => openPluginModal(Vencord.Plugins.plugins.Settings)}
|
||||||
>
|
>
|
||||||
settings of the Settings plugin
|
settings of the Settings plugin
|
||||||
|
|
@ -228,9 +232,9 @@ function EquicordSettings() {
|
||||||
s.warning.enabled ? (
|
s.warning.enabled ? (
|
||||||
<>
|
<>
|
||||||
{s.description}
|
{s.description}
|
||||||
<div className="form-switch-warning">
|
<Alert.Warning className={Margins.top8} style={{ width: "100%" }}>
|
||||||
{s.warning.message}
|
{s.warning.message}
|
||||||
</div>
|
</Alert.Warning>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
s.description
|
s.description
|
||||||
|
|
@ -332,16 +336,10 @@ function DonateButtonComponent() {
|
||||||
return (
|
return (
|
||||||
<Flex>
|
<Flex>
|
||||||
<DonateButton
|
<DonateButton
|
||||||
look={Button.Looks.FILLED}
|
equicord={true}
|
||||||
color={Button.Colors.TRANSPARENT}
|
style={{ marginTop: "1em" }} />
|
||||||
style={{ marginTop: "1em" }}
|
|
||||||
link="https://github.com/sponsors/thororen1234"
|
|
||||||
/>
|
|
||||||
<InviteButton
|
<InviteButton
|
||||||
look={Button.Looks.FILLED}
|
style={{ marginTop: "1em" }} />
|
||||||
color={Button.Colors.TRANSPARENT}
|
|
||||||
style={{ marginTop: "1em" }}
|
|
||||||
/>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
.plugin-warning {
|
|
||||||
font-size: 16px !important;
|
|
||||||
background-color: var(--info-warning-background) !important;
|
|
||||||
color: var(--info-warning-foreground) !important;
|
|
||||||
border: 1px solid var(--info-warning-foreground) !important;
|
|
||||||
border-radius: 5px !important;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 6px 10px;
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
@ -17,13 +17,13 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: '"view-profile"',
|
find: '"view-profile"',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(user:(\i).*?"PRESS_VIEW_PROFILE".{0,200})return/,
|
match: /(user:(\i).*?"PRESS_VIEW_PROFILE".{0,200}return)/,
|
||||||
replace: "$1return $self.openUserProfile($2);"
|
replace: "$1 $self.openUserModal($2);"
|
||||||
},
|
},
|
||||||
all: true
|
all: true
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
openUserProfile(user: User) {
|
openUserModal(user: User) {
|
||||||
openUserProfile(user.id);
|
openUserProfile(user.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,6 @@ export default definePlugin({
|
||||||
name: "DecodeBase64",
|
name: "DecodeBase64",
|
||||||
description: "Decode base64 content of any message and copy the decoded content.",
|
description: "Decode base64 content of any message and copy the decoded content.",
|
||||||
authors: [EquicordDevs.ThePirateStoner],
|
authors: [EquicordDevs.ThePirateStoner],
|
||||||
dependencies: ["MessagePopoverAPI"],
|
|
||||||
settings,
|
settings,
|
||||||
messagePopoverButton: {
|
messagePopoverButton: {
|
||||||
icon: DecodeIcon,
|
icon: DecodeIcon,
|
||||||
|
|
|
||||||
|
|
@ -163,8 +163,8 @@ export function Boo({ channel }: { channel: Channel; }) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if exempted, remove from ghost tracking
|
// if exempted or bot (if setting enabled), remove from ghost tracking
|
||||||
if (isExempted) {
|
if (isExempted || (settings.store.ignoreBots && lastMessage.author.bot)) {
|
||||||
if (countedChannels.has(id)) {
|
if (countedChannels.has(id)) {
|
||||||
countedChannels.delete(id);
|
countedChannels.delete(id);
|
||||||
setBooCount(getBooCount() - 1);
|
setBooCount(getBooCount() - 1);
|
||||||
|
|
@ -186,7 +186,7 @@ export function Boo({ channel }: { channel: Channel; }) {
|
||||||
}
|
}
|
||||||
}, [state.isCurrentUser, state.isDataProcessed, id, lastMessage?.id]);
|
}, [state.isCurrentUser, state.isDataProcessed, id, lastMessage?.id]);
|
||||||
|
|
||||||
if (!state.isDataProcessed || !currentUserId || !lastMessage || state.isCurrentUser || isChannelExempted(id) || isCleared)
|
if (!state.isDataProcessed || !currentUserId || !lastMessage || state.isCurrentUser || isChannelExempted(id) || isCleared || (settings.store.ignoreBots && lastMessage.author.bot))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!settings.store.showDmIcons) return null;
|
if (!settings.store.showDmIcons) return null;
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,12 @@ export const settings = definePluginSettings({
|
||||||
description: "Something might happen if you ignore someone for too long...",
|
description: "Something might happen if you ignore someone for too long...",
|
||||||
default: false,
|
default: false,
|
||||||
restartNeeded: false
|
restartNeeded: false
|
||||||
|
},
|
||||||
|
ignoreBots: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Ignore DMs from bots",
|
||||||
|
default: true,
|
||||||
|
restartNeeded: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
import { addAudioProcessor, AudioProcessor, PreprocessAudioData, removeAudioProcessor } from "@api/AudioPlayer";
|
import { AudioProcessor, PreprocessAudioData } from "@api/AudioPlayer";
|
||||||
import { get as getFromDataStore } from "@api/DataStore";
|
import { get as getFromDataStore } from "@api/DataStore";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
|
|
@ -394,15 +394,12 @@ export default definePlugin({
|
||||||
name: "CustomSounds",
|
name: "CustomSounds",
|
||||||
description: "Customize Discord's sounds.",
|
description: "Customize Discord's sounds.",
|
||||||
authors: [Devs.ScattrdBlade, Devs.TheKodeToad],
|
authors: [Devs.ScattrdBlade, Devs.TheKodeToad],
|
||||||
dependencies: ["AudioPlayerAPI"],
|
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
getCustomSoundURL,
|
|
||||||
startAt: StartAt.Init,
|
startAt: StartAt.Init,
|
||||||
|
audioProcessor: getCustomSoundURL,
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
console.log("[CustomSounds] Plugin starting...");
|
console.log("[CustomSounds] Plugin starting...");
|
||||||
addAudioProcessor("CustomSounds", this.getCustomSoundURL);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await preloadDataURIs();
|
await preloadDataURIs();
|
||||||
|
|
@ -413,7 +410,6 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
removeAudioProcessor("CustomSounds");
|
|
||||||
console.log("[CustomSounds] Plugin stopped");
|
console.log("[CustomSounds] Plugin stopped");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2024 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { addMessagePreSendListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
|
||||||
import { Paragraph } from "@components/Paragraph";
|
|
||||||
import { Devs } from "@utils/constants";
|
|
||||||
import { t } from "@utils/translation";
|
|
||||||
import definePlugin from "@utils/types";
|
|
||||||
import { Alerts, ChannelStore, PermissionsBits, PermissionStore } from "@webpack/common";
|
|
||||||
|
|
||||||
import filterList from "./constants";
|
|
||||||
|
|
||||||
function escapeRegex(string) {
|
|
||||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
||||||
}
|
|
||||||
|
|
||||||
function warningEmbedNotice(trigger) {
|
|
||||||
return new Promise<boolean>(resolve => {
|
|
||||||
Alerts.show({
|
|
||||||
title: "Hold on!",
|
|
||||||
body: <div>
|
|
||||||
<Paragraph>
|
|
||||||
Your message contains a term on the automod preset list. (Term "{trigger}")
|
|
||||||
</Paragraph>
|
|
||||||
<Paragraph>
|
|
||||||
There is a high chance your message will be blocked and potentially moderated by a server moderator.
|
|
||||||
</Paragraph>
|
|
||||||
</div>,
|
|
||||||
confirmText: "Send Anyway",
|
|
||||||
cancelText: t("vencord.cancel"),
|
|
||||||
onConfirm: () => resolve(true),
|
|
||||||
onCloseCallback: () => setImmediate(() => resolve(false)),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMessage = async (channelId, messageObj) => {
|
|
||||||
const channel = ChannelStore.getChannel(channelId);
|
|
||||||
if (channel.isDM()) return { cancel: false };
|
|
||||||
if (PermissionStore.can(PermissionsBits.ADMINISTRATOR, channel) || PermissionStore.can(PermissionsBits.MANAGE_GUILD, channel)) return { cancel: false };
|
|
||||||
|
|
||||||
const escapedStrings = filterList.map(escapeRegex);
|
|
||||||
const regexString = escapedStrings.join("|");
|
|
||||||
const regex = new RegExp(`(${regexString})`, "i");
|
|
||||||
|
|
||||||
const matches = regex.exec(messageObj.content);
|
|
||||||
console.log(matches);
|
|
||||||
if (matches) {
|
|
||||||
if (!await warningEmbedNotice(matches[0])) {
|
|
||||||
return { cancel: true };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { cancel: false };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default definePlugin({
|
|
||||||
name: "DontFilterMe",
|
|
||||||
description: "Warns you if your message contains a term in the automod preset list",
|
|
||||||
authors: [Devs.Samwich],
|
|
||||||
dependencies: ["MessageEventsAPI"],
|
|
||||||
start() {
|
|
||||||
addMessagePreSendListener(handleMessage);
|
|
||||||
},
|
|
||||||
stop() {
|
|
||||||
removeMessagePreSendListener(handleMessage);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -4,8 +4,6 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "@equicordplugins/_misc/styles.css";
|
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs, EquicordDevs } from "@utils/constants";
|
import { Devs, EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
|
@ -14,12 +12,6 @@ import { PluginButtons } from "./pluginButtons";
|
||||||
import { PluginCards } from "./pluginCards";
|
import { PluginCards } from "./pluginCards";
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
disableCreateDMButton: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Disables the create dm button",
|
|
||||||
restartNeeded: true,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
disableDMContextMenu: {
|
disableDMContextMenu: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
description: "Disables the DM list context menu in favor of the x button",
|
description: "Disables the DM list context menu in favor of the x button",
|
||||||
|
|
@ -59,15 +51,6 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// Disable Giant Create DM Button
|
|
||||||
{
|
|
||||||
find: ".createDMButtonContainer,",
|
|
||||||
predicate: () => settings.store.disableCreateDMButton,
|
|
||||||
replacement: {
|
|
||||||
match: /"create-dm"\)/,
|
|
||||||
replace: "$&&&false"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Remove DM Context Menu
|
// Remove DM Context Menu
|
||||||
{
|
{
|
||||||
find: "#{intl::DM_OPTIONS}",
|
find: "#{intl::DM_OPTIONS}",
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,12 @@
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
|
import { addHeaderBarButton, removeHeaderBarButton } from "@api/HeaderBar";
|
||||||
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findComponentByCodeLazy } from "@webpack";
|
import { findComponentByCodeLazy } from "@webpack";
|
||||||
import { Popout, useRef, useState } from "@webpack/common";
|
import { Popout, useRef, useState } from "@webpack/common";
|
||||||
import type { PropsWithChildren } from "react";
|
|
||||||
|
|
||||||
import { renderPopout } from "./menu";
|
import { renderPopout } from "./menu";
|
||||||
|
|
||||||
|
|
@ -48,7 +47,7 @@ function Icon() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function VencordPopoutButton({ buttonClass }: { buttonClass: string; }) {
|
function VencordPopoutButton() {
|
||||||
const buttonRef = useRef(null);
|
const buttonRef = useRef(null);
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
|
|
||||||
|
|
@ -66,10 +65,10 @@ function VencordPopoutButton({ buttonClass }: { buttonClass: string; }) {
|
||||||
{(_, { isShown }) => (
|
{(_, { isShown }) => (
|
||||||
<HeaderBarIcon
|
<HeaderBarIcon
|
||||||
ref={buttonRef}
|
ref={buttonRef}
|
||||||
className={`vc-toolbox-btn ${buttonClass}`}
|
className="vc-toolbox-btn"
|
||||||
onClick={() => setShow(v => !v)}
|
onClick={() => setShow(v => !v)}
|
||||||
tooltip={isShown ? null : "Equicord Toolbox"}
|
tooltip={isShown ? null : "Equicord Toolbox"}
|
||||||
icon={() => <Icon />}
|
icon={Icon}
|
||||||
selected={isShown}
|
selected={isShown}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
@ -82,27 +81,15 @@ export default definePlugin({
|
||||||
name: "EquicordToolbox",
|
name: "EquicordToolbox",
|
||||||
description: "Adds a button next to the inbox button in the channel header that houses Equicord quick actions",
|
description: "Adds a button next to the inbox button in the channel header that houses Equicord quick actions",
|
||||||
authors: [Devs.Ven, Devs.AutumnVN],
|
authors: [Devs.Ven, Devs.AutumnVN],
|
||||||
|
dependencies: ["HeaderBarAPI"],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
patches: [
|
start() {
|
||||||
{
|
addHeaderBarButton("EquicordToolbox", VencordPopoutButton, 1000);
|
||||||
find: '?"BACK_FORWARD_NAVIGATION":',
|
|
||||||
replacement: {
|
|
||||||
match: /(?<=trailing:.{0,50})\i\.Fragment,\{(?=.+?className:(\i))/,
|
|
||||||
replace: "$self.TrailingWrapper,{className:$1,"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
TrailingWrapper({ children, className }: PropsWithChildren<{ className: string; }>) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{children}
|
|
||||||
<ErrorBoundary noop>
|
|
||||||
<VencordPopoutButton buttonClass={className} />
|
|
||||||
</ErrorBoundary>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
removeHeaderBarButton("EquicordToolbox");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
* 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 { removeMessagePopoverButton } from "@api/MessagePopover";
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { disableStyle, enableStyle } from "@api/Styles";
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
|
@ -154,7 +153,6 @@ export default definePlugin({
|
||||||
enableStyle(styles);
|
enableStyle(styles);
|
||||||
},
|
},
|
||||||
stop() {
|
stop() {
|
||||||
removeMessagePopoverButton("vc-findreply");
|
|
||||||
root && root.unmount();
|
root && root.unmount();
|
||||||
element?.remove();
|
element?.remove();
|
||||||
disableStyle(styles);
|
disableStyle(styles);
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,9 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "@equicordplugins/_misc/styles.css";
|
|
||||||
|
|
||||||
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Paragraph } from "@components/Paragraph";
|
import { Alert } from "@components/Alert";
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { Channel, User, VoiceState } from "@vencord/discord-types";
|
import { Channel, User, VoiceState } from "@vencord/discord-types";
|
||||||
|
|
@ -79,11 +77,11 @@ export default definePlugin({
|
||||||
description: "Follow a friend in voice chat.",
|
description: "Follow a friend in voice chat.",
|
||||||
authors: [EquicordDevs.TheArmagan],
|
authors: [EquicordDevs.TheArmagan],
|
||||||
settings,
|
settings,
|
||||||
settingsAboutComponent: () => <>
|
settingsAboutComponent: () => (
|
||||||
<Paragraph className="plugin-warning">
|
<Alert.Info>
|
||||||
This Plugin is used to follow a Friend/Friends into voice chat(s).
|
This Plugin is used to follow a Friend/Friends into voice chat(s).
|
||||||
</Paragraph>
|
</Alert.Info>
|
||||||
</>,
|
),
|
||||||
flux: {
|
flux: {
|
||||||
async VOICE_STATE_UPDATES({ voiceStates }: { voiceStates: VoiceState[]; }) {
|
async VOICE_STATE_UPDATES({ voiceStates }: { voiceStates: VoiceState[]; }) {
|
||||||
if (!followedUserInfo) return;
|
if (!followedUserInfo) return;
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "#{intl::MESSAGE_FORWARDING_NSFW_NOT_ALLOWED}",
|
find: "#{intl::MESSAGE_FORWARDING_NSFW_NOT_ALLOWED}",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /if\(.{0,50}\)(return.{0,25}#{intl::MESSAGE_FORWARDING_NSFW_NOT_ALLOWED})/,
|
match: /(\{if\().{0,50}(\)return.{0,25}#{intl::MESSAGE_FORWARDING_NSFW_NOT_ALLOWED})/,
|
||||||
replace: "if(false)$1",
|
replace: "$1false$2",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2025 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { React, Tooltip, UserStore } from "@webpack/common";
|
|
||||||
import { JSX } from "react";
|
|
||||||
|
|
||||||
import { openBadgeModal } from "./badgeModal";
|
|
||||||
import { settings } from "./settings";
|
|
||||||
import { BadgeCache } from "./types";
|
|
||||||
import { cl, fetchBadges } from "./utils";
|
|
||||||
|
|
||||||
interface BadgeModalItem {
|
|
||||||
name: string;
|
|
||||||
rawName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export let badgeData;
|
|
||||||
|
|
||||||
export const BadgeComponent = ({ name, img }: { name: string, img: string; }) => {
|
|
||||||
return (
|
|
||||||
<Tooltip text={name} >
|
|
||||||
{(tooltipProps: any) => (
|
|
||||||
<img
|
|
||||||
{...tooltipProps}
|
|
||||||
src={img}
|
|
||||||
className={cl("badge")}
|
|
||||||
style={{
|
|
||||||
transform: name.includes("Replugged") ? "scale(0.9)" : null
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GlobalBadges = ({ userId }: { userId: string; }) => {
|
|
||||||
const [badges, setBadges] = React.useState<BadgeCache["badges"]>({});
|
|
||||||
React.useEffect(() => setBadges(fetchBadges(userId) ?? {}), [userId]);
|
|
||||||
|
|
||||||
if (!badges) return null;
|
|
||||||
const globalBadges: JSX.Element[] = [];
|
|
||||||
const badgeModal: BadgeModalItem[] = [];
|
|
||||||
|
|
||||||
Object.keys(badges).forEach(mod => {
|
|
||||||
if (!badges[mod] || !Array.isArray(badges[mod]) || badges[mod].length === 0) return;
|
|
||||||
|
|
||||||
badges[mod].forEach(badge => {
|
|
||||||
if (!badge || !badge.tooltip || !badge.badge) return;
|
|
||||||
|
|
||||||
const prefix = settings.store.showPrefix ? `(${mod})` : "";
|
|
||||||
const suffix = settings.store.showSuffix ? `(${mod})` : "";
|
|
||||||
const displayName = `${prefix} ${badge.tooltip} ${suffix}`;
|
|
||||||
|
|
||||||
if (mod === "BadgeVault") {
|
|
||||||
badge.custom = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalBadges.push(<BadgeComponent name={displayName} img={badge.badge} />);
|
|
||||||
badgeModal.push({
|
|
||||||
name: displayName,
|
|
||||||
rawName: badge.tooltip,
|
|
||||||
...badge
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
badgeData = badgeModal;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cl("badges")}
|
|
||||||
onClick={_ => openBadgeModal(UserStore.getUser(userId))}
|
|
||||||
>
|
|
||||||
{globalBadges}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -13,18 +13,18 @@ import { ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@u
|
||||||
import { User } from "@vencord/discord-types";
|
import { User } from "@vencord/discord-types";
|
||||||
import { React, Tooltip } from "@webpack/common";
|
import { React, Tooltip } from "@webpack/common";
|
||||||
|
|
||||||
import { badgeData } from "./badgeComponent";
|
import { cl, GlobalBadges, INVITE_LINK } from "./utils";
|
||||||
import { cl, INVITE_LINK } from "./utils";
|
|
||||||
|
|
||||||
export const BadgeModalComponent = ({ name, img }: { name: string, img: string; }) => {
|
export const BadgeModalComponent = ({ key, tooltip, badge }: { key: string, tooltip: string, badge: string; }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip text={name} >
|
<Tooltip text={tooltip} >
|
||||||
{(tooltipProps: any) => (
|
{(tooltipProps: any) => (
|
||||||
<img
|
<img
|
||||||
className={cl("modal-badge")}
|
className={cl("modal-badge")}
|
||||||
|
key={key}
|
||||||
{...tooltipProps}
|
{...tooltipProps}
|
||||||
src={img}
|
src={badge}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
@ -33,8 +33,8 @@ export const BadgeModalComponent = ({ name, img }: { name: string, img: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function openBadgeModal(user: User) {
|
export function openBadgeModal(user: User) {
|
||||||
const badgeDataElements = badgeData.map(badge => (
|
const badgeDataElements = GlobalBadges[user.id].map(badge => (
|
||||||
<BadgeModalComponent key={badge.rawName} name={badge.name} img={badge.badge} />
|
<BadgeModalComponent key={badge.key} tooltip={badge.tooltip} badge={badge.badge} />
|
||||||
));
|
));
|
||||||
|
|
||||||
openModal(modalprops => (
|
openModal(modalprops => (
|
||||||
|
|
|
||||||
|
|
@ -6,23 +6,19 @@
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
import { addProfileBadge, BadgePosition, ProfileBadge, removeProfileBadge } from "@api/Badges";
|
import { BadgePosition, ProfileBadge } from "@api/Badges";
|
||||||
import { Button } from "@components/Button";
|
import { Button } from "@components/Button";
|
||||||
|
import { BadgeContextMenu } from "@plugins/_api/badges";
|
||||||
import { Devs, EquicordDevs } from "@utils/constants";
|
import { Devs, EquicordDevs } from "@utils/constants";
|
||||||
import { openInviteModal } from "@utils/discord";
|
import { openInviteModal } from "@utils/discord";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { React } from "@webpack/common";
|
import { ContextMenuApi, React, Toasts, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
import { GlobalBadges } from "./badgeComponent";
|
import { openBadgeModal } from "./badgeModal";
|
||||||
import { settings } from "./settings";
|
import { settings } from "./settings";
|
||||||
import { cl, fetchBadges, INVITE_LINK } from "./utils";
|
import { cl, GlobalBadges, INVITE_LINK, loadBadges } from "./utils";
|
||||||
|
|
||||||
const Badge: ProfileBadge = {
|
let intervalId: any;
|
||||||
component: b => <GlobalBadges {...b} />,
|
|
||||||
position: BadgePosition.START,
|
|
||||||
shouldShow: userInfo => !!Object.keys(fetchBadges(userInfo.userId) ?? {}).length,
|
|
||||||
key: "GlobalBadges"
|
|
||||||
};
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "GlobalBadges",
|
name: "GlobalBadges",
|
||||||
|
|
@ -40,6 +36,44 @@ export default definePlugin({
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
start: () => addProfileBadge(Badge),
|
async start() {
|
||||||
stop: () => removeProfileBadge(Badge),
|
await loadBadges();
|
||||||
|
clearInterval(intervalId);
|
||||||
|
intervalId = setInterval(loadBadges, 1000 * 60 * 30);
|
||||||
|
},
|
||||||
|
async stop() {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
},
|
||||||
|
toolboxActions: {
|
||||||
|
async "Refetch Global Badges"() {
|
||||||
|
await loadBadges();
|
||||||
|
Toasts.show({
|
||||||
|
id: Toasts.genId(),
|
||||||
|
message: "Successfully refetched global badges!",
|
||||||
|
type: Toasts.Type.SUCCESS
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get GlobalBadges() {
|
||||||
|
return GlobalBadges;
|
||||||
|
},
|
||||||
|
getGlobalBadges(userId: string) {
|
||||||
|
return GlobalBadges[userId]?.map(badge => ({
|
||||||
|
iconSrc: badge.badge,
|
||||||
|
description: badge.tooltip,
|
||||||
|
position: BadgePosition.START,
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
borderRadius: "50%",
|
||||||
|
transform: "scale(0.9)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onContextMenu(event, badge) {
|
||||||
|
ContextMenuApi.openContextMenu(event, () => <BadgeContextMenu badge={badge} />);
|
||||||
|
},
|
||||||
|
onClick() {
|
||||||
|
return openBadgeModal(UserStore.getUser(userId));
|
||||||
|
},
|
||||||
|
} satisfies ProfileBadge));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,6 @@ export const settings = definePluginSettings({
|
||||||
default: true,
|
default: true,
|
||||||
restartNeeded: false
|
restartNeeded: false
|
||||||
},
|
},
|
||||||
showReplugged: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Show Replugged Badges",
|
|
||||||
default: true,
|
|
||||||
restartNeeded: false
|
|
||||||
},
|
|
||||||
apiUrl: {
|
apiUrl: {
|
||||||
type: OptionType.STRING,
|
type: OptionType.STRING,
|
||||||
description: "API to use",
|
description: "API to use",
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,3 @@
|
||||||
.vc-global-badges-badges {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-global-badges-badge {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
gap: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-global-badges-modal-name {
|
.vc-global-badges-modal-name {
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2025 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type CustomBadge = {
|
|
||||||
tooltip: string;
|
|
||||||
badge: string;
|
|
||||||
custom?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface BadgeCache {
|
|
||||||
badges: { [mod: string]: CustomBadge[]; };
|
|
||||||
expires: number;
|
|
||||||
}
|
|
||||||
|
|
@ -4,44 +4,67 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import "./styles.css";
|
||||||
|
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
|
|
||||||
import { settings } from "./settings";
|
import { settings } from "./settings";
|
||||||
import { BadgeCache } from "./types";
|
|
||||||
|
|
||||||
const cache = new Map<string, BadgeCache>();
|
export let GlobalBadges = {};
|
||||||
const EXPIRES = 1000 * 60 * 15;
|
|
||||||
|
|
||||||
export const cl = classNameFactory("vc-global-badges-");
|
|
||||||
export const INVITE_LINK = "kwHCJPxp8t";
|
export const INVITE_LINK = "kwHCJPxp8t";
|
||||||
|
export const cl = classNameFactory("vc-global-badges-");
|
||||||
export const fetchBadges = (id: string): BadgeCache["badges"] | undefined => {
|
export const serviceMap: Record<string, string> = {
|
||||||
const cachedValue = cache.get(id);
|
nekocord: "Nekocord",
|
||||||
if (!cache.has(id) || (cachedValue && cachedValue.expires < Date.now())) {
|
reviewdb: "ReviewDB",
|
||||||
const services: string[] = [];
|
aero: "Aero",
|
||||||
if (settings.store.showNekocord) services.push("nekocord");
|
aliucord: "Aliucord",
|
||||||
if (settings.store.showReviewDB) services.push("reviewdb");
|
ra1ncord: "Ra1ncord",
|
||||||
if (settings.store.showAero) services.push("aero");
|
velocity: "Velocity",
|
||||||
if (settings.store.showAliucord) services.push("aliucord");
|
enmity: "Enmity",
|
||||||
if (settings.store.showRa1ncord) services.push("ra1ncord");
|
badgevault: "BadgeVault",
|
||||||
if (settings.store.showVelocity) services.push("velocity");
|
vencord: "Vencord",
|
||||||
if (settings.store.showEnmity) services.push("enmity");
|
equicord: "Equicord",
|
||||||
if (settings.store.showReplugged) services.push("replugged");
|
|
||||||
if (settings.store.showCustom) services.push("badgevault");
|
|
||||||
|
|
||||||
if (services.length === 0) {
|
|
||||||
cache.set(id, { badges: {}, expires: Date.now() + EXPIRES });
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch(`${settings.store.apiUrl}${id}?seperated=true&capitalize=true&services=${services.join(",")}`)
|
|
||||||
.then(res => res.json() as Promise<{ status: number; badges: BadgeCache["badges"]; }>)
|
|
||||||
.then(body => {
|
|
||||||
cache.set(id, { badges: body.badges, expires: Date.now() + EXPIRES });
|
|
||||||
return body.badges;
|
|
||||||
})
|
|
||||||
.catch(() => null);
|
|
||||||
} else if (cachedValue) {
|
|
||||||
return cachedValue.badges;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function loadBadges() {
|
||||||
|
const url = settings.store.apiUrl.endsWith("/") ? settings.store.apiUrl + "users" : settings.store.apiUrl + "/users";
|
||||||
|
const globalBadges = await fetch(url, { cache: "no-cache" }).then(r => r.json());
|
||||||
|
const filteredUsers: Record<string, typeof globalBadges.users[string]> = {};
|
||||||
|
|
||||||
|
for (const key in globalBadges.users) {
|
||||||
|
filteredUsers[key] = globalBadges.users[key].filter(b => {
|
||||||
|
const { mod } = b;
|
||||||
|
if (!mod) return false;
|
||||||
|
|
||||||
|
const blockedMods = ["vencord", "equicord"];
|
||||||
|
if (blockedMods.includes(mod)) return false;
|
||||||
|
|
||||||
|
const conditionalMods = {
|
||||||
|
aero: settings.store.showAero,
|
||||||
|
velocity: settings.store.showVelocity,
|
||||||
|
badgevault: settings.store.showCustom,
|
||||||
|
nekocord: settings.store.showNekocord,
|
||||||
|
reviewdb: settings.store.showReviewDB,
|
||||||
|
aliucord: settings.store.showAliucord,
|
||||||
|
ra1ncord: settings.store.showRa1ncord,
|
||||||
|
enmity: settings.store.showEnmity
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mod in conditionalMods && !conditionalMods[mod]) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}).map(b => {
|
||||||
|
const modFormatted = serviceMap[b.mod];
|
||||||
|
const prefix = settings.store.showPrefix ? `${modFormatted} - ` : "";
|
||||||
|
const suffix = settings.store.showSuffix ? ` - ${modFormatted}` : "";
|
||||||
|
const tooltip = prefix + b.tooltip + suffix;
|
||||||
|
return {
|
||||||
|
...b,
|
||||||
|
key: b.tooltip,
|
||||||
|
tooltip
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalBadges = filteredUsers;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,205 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2024 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
|
||||||
import { DataStore } from "@api/index";
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
|
||||||
import { Button } from "@components/Button";
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Heading } from "@components/Heading";
|
|
||||||
import { EquicordDevs } from "@utils/constants";
|
|
||||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
|
|
||||||
import { t } from "@utils/translation";
|
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
|
||||||
import { Message, User } from "@vencord/discord-types";
|
|
||||||
import { findComponentByCodeLazy } from "@webpack";
|
|
||||||
import { Menu, React, TextInput, UserStore } from "@webpack/common";
|
|
||||||
|
|
||||||
const UserBoxIcon = findComponentByCodeLazy("0-3-3H5Zm10 6a3");
|
|
||||||
|
|
||||||
type NicknamesData = Record<string, string>;
|
|
||||||
|
|
||||||
let nicknames: NicknamesData = {};
|
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
|
||||||
enableMessages: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Show global nicknames in chat messages.",
|
|
||||||
default: true,
|
|
||||||
restartNeeded: true
|
|
||||||
},
|
|
||||||
enableMemberList: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Show global nicknames in the member list.",
|
|
||||||
default: true,
|
|
||||||
restartNeeded: true
|
|
||||||
},
|
|
||||||
enableVoiceChannels: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Show global nicknames in voice channels.",
|
|
||||||
default: true,
|
|
||||||
restartNeeded: true
|
|
||||||
},
|
|
||||||
enableTypingIndicator: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Show global nicknames in the typing indicator.",
|
|
||||||
default: true,
|
|
||||||
restartNeeded: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function NicknameModal({ modalProps, user }: { modalProps: ModalProps; user: User; }) {
|
|
||||||
const [value, setValue] = React.useState(nicknames[user.id] ?? "");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ModalRoot {...modalProps}>
|
|
||||||
<ModalHeader>
|
|
||||||
<Heading tag="h2" style={{ flexGrow: 1, margin: 0 }}>
|
|
||||||
Change Nickname
|
|
||||||
</Heading>
|
|
||||||
<ModalCloseButton onClick={modalProps.onClose} />
|
|
||||||
</ModalHeader>
|
|
||||||
<ModalContent>
|
|
||||||
<div style={{ marginBottom: 20 }}>
|
|
||||||
<Heading tag="h3" style={{ marginBottom: 8, fontSize: "14px", fontWeight: 600 }}>
|
|
||||||
Nickname
|
|
||||||
</Heading>
|
|
||||||
<TextInput
|
|
||||||
value={value}
|
|
||||||
onChange={setValue}
|
|
||||||
placeholder={user.globalName ?? user.username}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ModalContent>
|
|
||||||
<ModalFooter>
|
|
||||||
<Button
|
|
||||||
variant="primary"
|
|
||||||
onClick={async () => {
|
|
||||||
const trimmed = value.trim();
|
|
||||||
if (trimmed) {
|
|
||||||
nicknames[user.id] = trimmed;
|
|
||||||
} else {
|
|
||||||
delete nicknames[user.id];
|
|
||||||
}
|
|
||||||
await DataStore.set("GlobalNicknames", nicknames);
|
|
||||||
modalProps.onClose();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
style={{ marginRight: "8px" }}
|
|
||||||
onClick={modalProps.onClose}
|
|
||||||
>
|
|
||||||
{t("vencord.cancel")}
|
|
||||||
</Button>
|
|
||||||
</ModalFooter>
|
|
||||||
</ModalRoot>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const userContextPatch: NavContextMenuPatchCallback = (children, { user }) => {
|
|
||||||
if (!user) return;
|
|
||||||
|
|
||||||
const currentUser = UserStore.getCurrentUser();
|
|
||||||
if (!currentUser || user.id === currentUser.id) return;
|
|
||||||
|
|
||||||
children.push(
|
|
||||||
<Menu.MenuSeparator />,
|
|
||||||
nicknames[user.id] ? (
|
|
||||||
<Menu.MenuItem
|
|
||||||
id="remove-nickname"
|
|
||||||
label="Remove Nickname"
|
|
||||||
color="danger"
|
|
||||||
icon={UserBoxIcon}
|
|
||||||
action={async () => {
|
|
||||||
delete nicknames[user.id];
|
|
||||||
await DataStore.set("GlobalNicknames", nicknames);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Menu.MenuItem
|
|
||||||
id="change-nickname"
|
|
||||||
label="Change Nickname"
|
|
||||||
icon={UserBoxIcon}
|
|
||||||
action={() => openModal(props => (
|
|
||||||
<ErrorBoundary>
|
|
||||||
<NicknameModal modalProps={props} user={user} />
|
|
||||||
</ErrorBoundary>
|
|
||||||
))}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default definePlugin({
|
|
||||||
name: "GlobalNicknames",
|
|
||||||
description: "Set custom nicknames for any user globally.",
|
|
||||||
authors: [EquicordDevs.Prism],
|
|
||||||
dependencies: ["ContextMenuAPI"],
|
|
||||||
settings,
|
|
||||||
|
|
||||||
patches: [
|
|
||||||
{
|
|
||||||
find: '="SYSTEM_TAG"',
|
|
||||||
predicate: () => settings.store.enableMessages,
|
|
||||||
replacement: {
|
|
||||||
match: /children:(.+?),"data-text":/,
|
|
||||||
replace: 'children:$self.patchMessageName(arguments[0])??($1),"data-text":'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
find: "let{colorRoleName:",
|
|
||||||
predicate: () => settings.store.enableMemberList,
|
|
||||||
replacement: {
|
|
||||||
match: /,name:(null!=\i\?\i:\i),colorStrings/,
|
|
||||||
replace: ",name:$self.patchName($1,arguments[0].user)||($1),colorStrings"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
find: ",connectUserDragSource:",
|
|
||||||
predicate: () => settings.store.enableVoiceChannels,
|
|
||||||
replacement: {
|
|
||||||
match: /nick:(\i),collapsed/,
|
|
||||||
replace: "nick:$self.patchName($1,arguments[0].user)||$1,collapsed"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
find: "#{intl::THREE_USERS_TYPING}",
|
|
||||||
predicate: () => settings.store.enableTypingIndicator,
|
|
||||||
replacement: {
|
|
||||||
match: /(\i\.\i\.getName\(\i\.guild_id,\i\.id),(\i)\)\)/,
|
|
||||||
replace: "$1,$self.patchTypingName($2)))"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
async start() {
|
|
||||||
const data = await DataStore.get<NicknamesData>("GlobalNicknames");
|
|
||||||
nicknames = data ?? {};
|
|
||||||
},
|
|
||||||
|
|
||||||
patchMessageName(props: { message: Message; }): string | null {
|
|
||||||
const userId = props?.message?.author?.id;
|
|
||||||
return userId ? nicknames[userId] ?? null : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
patchName(_: string, user: User): string | null {
|
|
||||||
return nicknames[user.id] ?? null;
|
|
||||||
},
|
|
||||||
|
|
||||||
patchTypingName(user: User): User {
|
|
||||||
const nickname = nicknames[user.id];
|
|
||||||
if (!nickname) return user;
|
|
||||||
return { ...user, globalName: nickname, username: nickname } as User;
|
|
||||||
},
|
|
||||||
|
|
||||||
contextMenus: {
|
|
||||||
"user-context": userContextPatch
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -16,8 +16,6 @@
|
||||||
* 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 "@equicordplugins/_misc/styles.css";
|
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { disableStyle, enableStyle } from "@api/Styles";
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,6 @@ import "./style.css";
|
||||||
|
|
||||||
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { DataStore } from "@api/index";
|
import { DataStore } from "@api/index";
|
||||||
import { removeMessagePopoverButton } from "@api/MessagePopover";
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { openModal } from "@utils/modal";
|
import { openModal } from "@utils/modal";
|
||||||
|
|
@ -58,15 +56,13 @@ function ToolBarHeader() {
|
||||||
const iconClasses = findByProps("iconWrapper", "clickable");
|
const iconClasses = findByProps("iconWrapper", "clickable");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary noop={true}>
|
<HeaderBarIcon
|
||||||
<HeaderBarIcon
|
tooltip="Holy Notes"
|
||||||
tooltip="Holy Notes"
|
position="bottom"
|
||||||
position="bottom"
|
className={classes("vc-note-button", iconClasses.iconWrapper, iconClasses.clickable)}
|
||||||
className={classes("vc-note-button", iconClasses.iconWrapper, iconClasses.clickable)}
|
icon={Popover}
|
||||||
icon={e => Popover(e)}
|
onClick={() => openModal(props => <NoteModal {...props} />)}
|
||||||
onClick={() => openModal(props => <NoteModal {...props} />)}
|
/>
|
||||||
/>
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,17 +71,6 @@ export default definePlugin({
|
||||||
name: "HolyNotes",
|
name: "HolyNotes",
|
||||||
description: "Holy Notes allows you to save messages",
|
description: "Holy Notes allows you to save messages",
|
||||||
authors: [EquicordDevs.Wolfie],
|
authors: [EquicordDevs.Wolfie],
|
||||||
dependencies: ["MessagePopoverAPI", "ChatInputButtonAPI"],
|
|
||||||
|
|
||||||
patches: [
|
|
||||||
{
|
|
||||||
find: ".controlButtonWrapper,",
|
|
||||||
replacement: {
|
|
||||||
match: /(function \i\(\i\){)(.{1,200}toolbar.{1,100}mobileToolbar)/,
|
|
||||||
replace: "$1$self.toolbarAction(arguments[0]);$2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
toolboxActions: {
|
toolboxActions: {
|
||||||
async "Open Notes"() {
|
async "Open Notes"() {
|
||||||
|
|
@ -97,21 +82,8 @@ export default definePlugin({
|
||||||
"message": messageContextMenuPatch
|
"message": messageContextMenuPatch
|
||||||
},
|
},
|
||||||
|
|
||||||
toolbarAction(e) {
|
renderHeaderBarButton: ToolBarHeader,
|
||||||
if (Array.isArray(e.toolbar))
|
|
||||||
return e.toolbar.unshift(
|
|
||||||
<ErrorBoundary noop={true}>
|
|
||||||
<ToolBarHeader />
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
|
||||||
|
|
||||||
e.toolbar = [
|
|
||||||
<ErrorBoundary noop={true} key={"HolyNotes"}>
|
|
||||||
<ToolBarHeader />
|
|
||||||
</ErrorBoundary>,
|
|
||||||
e.toolbar,
|
|
||||||
];
|
|
||||||
},
|
|
||||||
messagePopoverButton: {
|
messagePopoverButton: {
|
||||||
icon: NoteButtonPopover,
|
icon: NoteButtonPopover,
|
||||||
render(message) {
|
render(message) {
|
||||||
|
|
@ -129,8 +101,4 @@ export default definePlugin({
|
||||||
if (await DataStore.keys(HolyNoteStore).then(keys => !keys.includes("Main"))) return noteHandler.newNoteBook("Main");
|
if (await DataStore.keys(HolyNoteStore).then(keys => !keys.includes("Main"))) return noteHandler.newNoteBook("Main");
|
||||||
if (!noteHandlerCache.has("Main")) await DataStoreToCache();
|
if (!noteHandlerCache.has("Main")) await DataStoreToCache();
|
||||||
},
|
},
|
||||||
|
|
||||||
async stop() {
|
|
||||||
removeMessagePopoverButton("HolyNotes");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,6 @@ export default definePlugin({
|
||||||
name: "Husk",
|
name: "Husk",
|
||||||
description: "Adds Husk button (check settings to change used emoji)",
|
description: "Adds Husk button (check settings to change used emoji)",
|
||||||
authors: [Devs.nin0dev],
|
authors: [Devs.nin0dev],
|
||||||
dependencies: ["MessagePopoverAPI"],
|
|
||||||
settings,
|
settings,
|
||||||
messagePopoverButton: {
|
messagePopoverButton: {
|
||||||
icon: Husk,
|
icon: Husk,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
import { BaseText } from "@components/BaseText";
|
import { BaseText } from "@components/BaseText";
|
||||||
import { Flex } from "@components/Flex";
|
import { HeadingPrimary } from "@components/Heading";
|
||||||
import { Paragraph } from "@components/Paragraph";
|
import { Paragraph } from "@components/Paragraph";
|
||||||
import { openUserProfile } from "@utils/discord";
|
import { openUserProfile } from "@utils/discord";
|
||||||
import { Avatar, Clickable, React, TextInput, Tooltip, } from "@webpack/common";
|
import { Avatar, Clickable, React, TextInput, Tooltip, } from "@webpack/common";
|
||||||
|
|
@ -44,11 +44,9 @@ function UsersCollectionRows({ usersCollection }: { usersCollection: Data["users
|
||||||
.map(({ name, users }) => (
|
.map(({ name, users }) => (
|
||||||
<aside key={name}>
|
<aside key={name}>
|
||||||
<div className={cl("header-container")}>
|
<div className={cl("header-container")}>
|
||||||
<BaseText>{name.toUpperCase()}</BaseText>
|
<HeadingPrimary className={cl("header-name")}>{name}</HeadingPrimary>
|
||||||
<div className={cl("header-btns")}>
|
<div className={cl("header-btns")}>
|
||||||
<Flex>
|
{users.map(u => <UserRow key={u.id} user={u} />)}
|
||||||
{users.map(u => <UserRow key={u.id} user={u} />)}
|
|
||||||
</Flex>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
@ -59,14 +57,14 @@ function UsersCollectionRows({ usersCollection }: { usersCollection: Data["users
|
||||||
|
|
||||||
function UserRow({ user, allowOwner = true }: { user: IStorageUser, allowOwner?: boolean; }) {
|
function UserRow({ user, allowOwner = true }: { user: IStorageUser, allowOwner?: boolean; }) {
|
||||||
return (
|
return (
|
||||||
<Flex key={user.id} className={cl("user-row")}>
|
<div key={user.id} className={cl("user-row")}>
|
||||||
<span className={cl("user")}>
|
<div className={cl("user")}>
|
||||||
<Flex>
|
<Clickable onClick={() => openUserProfile(user.id)}>
|
||||||
<Clickable onClick={() => openUserProfile(user.id)}>
|
<span className={cl("user-avatar")}>
|
||||||
<span className={cl("user-avatar")}>
|
<Avatar src={user.iconURL} size="SIZE_24" />
|
||||||
<Avatar src={user.iconURL} size="SIZE_24" />
|
</span>
|
||||||
</span>
|
</Clickable>
|
||||||
</Clickable>
|
<div className={cl("user-tooltip")}>
|
||||||
<Tooltip text={tooltipText(user)}>
|
<Tooltip text={tooltipText(user)}>
|
||||||
{props =>
|
{props =>
|
||||||
<Paragraph {...props} className={cl("user-username")}>
|
<Paragraph {...props} className={cl("user-username")}>
|
||||||
|
|
@ -74,15 +72,14 @@ function UserRow({ user, allowOwner = true }: { user: IStorageUser, allowOwner?:
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
}
|
}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Flex>
|
<span className={cl("user-id")}>
|
||||||
</span>
|
<Paragraph>
|
||||||
|
{user.id}
|
||||||
<span className={cl("user-id")}>
|
</Paragraph>
|
||||||
<Paragraph>
|
</span>
|
||||||
{user.id}
|
</div>
|
||||||
</Paragraph>
|
</div>
|
||||||
</span>
|
</div>
|
||||||
</Flex>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,10 +91,10 @@ function SearchElement({ usersCollection }: { usersCollection: Data["usersCollec
|
||||||
<section className={cl("search")}>
|
<section className={cl("search")}>
|
||||||
<TextInput placeholder="Filter by tag, username" name="Filter" onChange={setCurrent} />
|
<TextInput placeholder="Filter by tag, username" name="Filter" onChange={setCurrent} />
|
||||||
{current && (
|
{current && (
|
||||||
<Flex className={cl("search-user")}>
|
<div className={cl("search-user")}>
|
||||||
{list.filter(user => user.tag.includes(current) || user.username.includes(current))
|
{list.filter(user => user.tag.includes(current) || user.username.includes(current))
|
||||||
.map(user => <UserRow key={user.id} user={user} allowOwner={false} />)}
|
.map(user => <UserRow key={user.id} user={user} allowOwner={false} />)}
|
||||||
</Flex>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
@ -112,9 +109,9 @@ export function DataUI({ plugin, usersCollection }: { plugin: any; usersCollecti
|
||||||
|
|
||||||
<SectionDescription />
|
<SectionDescription />
|
||||||
<SearchElement usersCollection={usersCollection} />
|
<SearchElement usersCollection={usersCollection} />
|
||||||
<Flex className={cl("rows")}>
|
<div className={cl("rows")}>
|
||||||
<UsersCollectionRows usersCollection={usersCollection} />
|
<UsersCollectionRows usersCollection={usersCollection} />
|
||||||
</Flex>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,15 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vc-i-remember-you-header-name {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.vc-i-remember-you-header-btns {
|
.vc-i-remember-you-header-btns {
|
||||||
gap: 8px;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 350px));
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-i-remember-you-header {
|
.vc-i-remember-you-header {
|
||||||
|
|
@ -29,49 +36,38 @@
|
||||||
|
|
||||||
.vc-i-remember-you-user-avatar {
|
.vc-i-remember-you-user-avatar {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-right: 30px;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-i-remember-you-user-row {
|
.vc-i-remember-you-user-row {
|
||||||
margin: 0;
|
display: flex;
|
||||||
width: 100%;
|
flex-direction: column;
|
||||||
flex-wrap: wrap;
|
gap: 6px;
|
||||||
align-items: center;
|
padding: 4px;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-i-remember-you-user-id {
|
.vc-i-remember-you-user-id {
|
||||||
height: min-content;
|
align-self: flex-start;
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
|
height: min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-i-remember-you-user {
|
.vc-i-remember-you-user {
|
||||||
width: 500px;
|
display: flex;
|
||||||
gap: 250px;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow-wrap: break-word;
|
gap: 8px;
|
||||||
margin-top: 5px;
|
width: 100%;
|
||||||
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-i-remember-you-user-username {
|
.vc-i-remember-you-user-username {
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-i-remember-you-buttons {
|
.vc-i-remember-you-user-tooltip {
|
||||||
margin-top: 10px;
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
.vc-i-remember-you-buttons-save,
|
|
||||||
.vc-i-remember-you-buttons-cancel {
|
|
||||||
margin-left: 490px;
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-i-remember-you-buttons-cancel {
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-i-remember-you-buttons-reset {
|
|
||||||
cursor: pointer;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
@ -79,24 +79,39 @@ const IngtoninatorButton: ChatBarButtonFactory = ({ isMainChat }) => {
|
||||||
onClick={toggle}
|
onClick={toggle}
|
||||||
>
|
>
|
||||||
{isEnabled ? (
|
{isEnabled ? (
|
||||||
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
enabledIcon()
|
||||||
<path transform="translate(351 -153)" fill="currentcolor" d="M-177.7,334.5c6.3-2.3,12.6-5.2,19.8-8.6c31.9-16.4,51.7-41.7,51.7-41.7s-32.5,0.6-64.4,17 c-4,1.7-7.5,4-10.9,5.7c5.7-7.5,12.1-16.4,18.7-25c25-37.1,31.3-77.3,31.3-77.3s-34.8,21-59.2,58.6c-5.2,7.5-9.8,14.9-13.8,22.7 c1.1-10.3,1.1-22.1,1.1-33.6c0-50-19.8-91.1-19.8-91.1s-19.8,40.5-19.8,91.1c0,12.1,0.6,23.3,1.1,33.6c-4-7.5-8.6-14.9-13.8-22.7 c-25-37.1-59.2-58.6-59.2-58.6s6.3,40,31.3,77.3c6.3,9.2,12.1,17.5,18.7,25c-3.4-2.3-7.5-4-10.9-5.7c-31.9-16.4-64.4-17-64.4-17 s19.8,25.6,51.7,41.7c6.9,3.4,13.2,6.3,19.8,8.6c-4,0.6-8,1.1-12.1,2.3c-30.5,6.4-53.2,23.9-53.2,23.9s27.3,7.5,58.6,1.1 c9.8-2.3,19.8-4.6,27.3-7.5c-1.1,1.1,15.8-8.6,21.6-14.4v60.4h8.6v-61.8c6.3,6.3,22.7,16.4,22.1,14.9c8,2.9,17.5,5.2,27.3,7.5 c30.8,6.3,58.6-1.1,58.6-1.1s-22.1-17.5-53.4-23.8C-169.6,335.7-173.7,335.1-177.7,334.5z" />
|
|
||||||
</svg>
|
|
||||||
) : (
|
) : (
|
||||||
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
disabledIcon()
|
||||||
<path transform="translate(351 -153)" fill="var(--status-danger)" d="M-177.7,334.5c6.3-2.3,12.6-5.2,19.8-8.6c31.9-16.4,51.7-41.7,51.7-41.7s-32.5,0.6-64.4,17 c-4,1.7-7.5,4-10.9,5.7c5.7-7.5,12.1-16.4,18.7-25c25-37.1,31.3-77.3,31.3-77.3s-34.8,21-59.2,58.6c-5.2,7.5-9.8,14.9-13.8,22.7 c1.1-10.3,1.1-22.1,1.1-33.6c0-50-19.8-91.1-19.8-91.1s-19.8,40.5-19.8,91.1c0,12.1,0.6,23.3,1.1,33.6c-4-7.5-8.6-14.9-13.8-22.7 c-25-37.1-59.2-58.6-59.2-58.6s6.3,40,31.3,77.3c6.3,9.2,12.1,17.5,18.7,25c-3.4-2.3-7.5-4-10.9-5.7c-31.9-16.4-64.4-17-64.4-17 s19.8,25.6,51.7,41.7c6.9,3.4,13.2,6.3,19.8,8.6c-4,0.6-8,1.1-12.1,2.3c-30.5,6.4-53.2,23.9-53.2,23.9s27.3,7.5,58.6,1.1 c9.8-2.3,19.8-4.6,27.3-7.5c-1.1,1.1,15.8-8.6,21.6-14.4v60.4h8.6v-61.8c6.3,6.3,22.7,16.4,22.1,14.9c8,2.9,17.5,5.2,27.3,7.5 c30.8,6.3,58.6-1.1,58.6-1.1s-22.1-17.5-53.4-23.8C-169.6,335.7-173.7,335.1-177.7,334.5z" />
|
|
||||||
</svg>
|
|
||||||
)}
|
)}
|
||||||
</ChatBarButton>
|
</ChatBarButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function enabledIcon() {
|
||||||
|
return (
|
||||||
|
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
||||||
|
<path transform="translate(351 -153)" fill="currentcolor" d="M-177.7,334.5c6.3-2.3,12.6-5.2,19.8-8.6c31.9-16.4,51.7-41.7,51.7-41.7s-32.5,0.6-64.4,17 c-4,1.7-7.5,4-10.9,5.7c5.7-7.5,12.1-16.4,18.7-25c25-37.1,31.3-77.3,31.3-77.3s-34.8,21-59.2,58.6c-5.2,7.5-9.8,14.9-13.8,22.7 c1.1-10.3,1.1-22.1,1.1-33.6c0-50-19.8-91.1-19.8-91.1s-19.8,40.5-19.8,91.1c0,12.1,0.6,23.3,1.1,33.6c-4-7.5-8.6-14.9-13.8-22.7 c-25-37.1-59.2-58.6-59.2-58.6s6.3,40,31.3,77.3c6.3,9.2,12.1,17.5,18.7,25c-3.4-2.3-7.5-4-10.9-5.7c-31.9-16.4-64.4-17-64.4-17 s19.8,25.6,51.7,41.7c6.9,3.4,13.2,6.3,19.8,8.6c-4,0.6-8,1.1-12.1,2.3c-30.5,6.4-53.2,23.9-53.2,23.9s27.3,7.5,58.6,1.1 c9.8-2.3,19.8-4.6,27.3-7.5c-1.1,1.1,15.8-8.6,21.6-14.4v60.4h8.6v-61.8c6.3,6.3,22.7,16.4,22.1,14.9c8,2.9,17.5,5.2,27.3,7.5 c30.8,6.3,58.6-1.1,58.6-1.1s-22.1-17.5-53.4-23.8C-169.6,335.7-173.7,335.1-177.7,334.5z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disabledIcon() {
|
||||||
|
return (
|
||||||
|
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
||||||
|
<path transform="translate(351 -153)" fill="var(--status-danger)" d="M-177.7,334.5c6.3-2.3,12.6-5.2,19.8-8.6c31.9-16.4,51.7-41.7,51.7-41.7s-32.5,0.6-64.4,17 c-4,1.7-7.5,4-10.9,5.7c5.7-7.5,12.1-16.4,18.7-25c25-37.1,31.3-77.3,31.3-77.3s-34.8,21-59.2,58.6c-5.2,7.5-9.8,14.9-13.8,22.7 c1.1-10.3,1.1-22.1,1.1-33.6c0-50-19.8-91.1-19.8-91.1s-19.8,40.5-19.8,91.1c0,12.1,0.6,23.3,1.1,33.6c-4-7.5-8.6-14.9-13.8-22.7 c-25-37.1-59.2-58.6-59.2-58.6s6.3,40,31.3,77.3c6.3,9.2,12.1,17.5,18.7,25c-3.4-2.3-7.5-4-10.9-5.7c-31.9-16.4-64.4-17-64.4-17 s19.8,25.6,51.7,41.7c6.9,3.4,13.2,6.3,19.8,8.6c-4,0.6-8,1.1-12.1,2.3c-30.5,6.4-53.2,23.9-53.2,23.9s27.3,7.5,58.6,1.1 c9.8-2.3,19.8-4.6,27.3-7.5c-1.1,1.1,15.8-8.6,21.6-14.4v60.4h8.6v-61.8c6.3,6.3,22.7,16.4,22.1,14.9c8,2.9,17.5,5.2,27.3,7.5 c30.8,6.3,58.6-1.1,58.6-1.1s-22.1-17.5-53.4-23.8C-169.6,335.7-173.7,335.1-177.7,334.5z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "Ingtoninator",
|
name: "Ingtoninator",
|
||||||
description: "Suffixes 'ington' to a random word in your message",
|
description: "Suffixes 'ington' to a random word in your message",
|
||||||
authors: [EquicordDevs.zyqunix],
|
authors: [EquicordDevs.zyqunix],
|
||||||
settings,
|
settings,
|
||||||
renderChatBarButton: IngtoninatorButton,
|
chatBarButton: {
|
||||||
|
icon: disabledIcon,
|
||||||
|
render: IngtoninatorButton
|
||||||
|
},
|
||||||
start() {
|
start() {
|
||||||
addMessagePreSendListener(handleMessage);
|
addMessagePreSendListener(handleMessage);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ function Indicator() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChatBarIcon: ChatBarButtonFactory = ({ isMainChat }) => {
|
const ChatBarRender: ChatBarButtonFactory = ({ isMainChat }) => {
|
||||||
if (!isMainChat) return null;
|
if (!isMainChat) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -76,20 +76,26 @@ const ChatBarIcon: ChatBarButtonFactory = ({ isMainChat }) => {
|
||||||
"aria-haspopup": "dialog",
|
"aria-haspopup": "dialog",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<svg
|
{ChatBarIcon()}
|
||||||
aria-hidden
|
|
||||||
role="img"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox={"0 0 64 64"}
|
|
||||||
style={{ scale: "1.39", translate: "0 -1px" }}
|
|
||||||
>
|
|
||||||
<path fill="currentColor" d="M 32 9 C 24.832 9 19 14.832 19 22 L 19 27.347656 C 16.670659 28.171862 15 30.388126 15 33 L 15 49 C 15 52.314 17.686 55 21 55 L 43 55 C 46.314 55 49 52.314 49 49 L 49 33 C 49 30.388126 47.329341 28.171862 45 27.347656 L 45 22 C 45 14.832 39.168 9 32 9 z M 32 13 C 36.963 13 41 17.038 41 22 L 41 27 L 23 27 L 23 22 C 23 17.038 27.037 13 32 13 z" />
|
|
||||||
</svg>
|
|
||||||
</ChatBarButton>
|
</ChatBarButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function ChatBarIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
aria-hidden
|
||||||
|
role="img"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox={"0 0 64 64"}
|
||||||
|
style={{ scale: "1.39", translate: "0 -1px" }}
|
||||||
|
>
|
||||||
|
<path fill="currentColor" d="M 32 9 C 24.832 9 19 14.832 19 22 L 19 27.347656 C 16.670659 28.171862 15 30.388126 15 33 L 15 49 C 15 52.314 17.686 55 21 55 L 43 55 C 46.314 55 49 52.314 49 49 L 49 33 C 49 30.388126 47.329341 28.171862 45 27.347656 L 45 22 C 45 14.832 39.168 9 32 9 z M 32 13 C 36.963 13 41 17.038 41 22 L 41 27 L 23 27 L 23 22 C 23 17.038 27.037 13 32 13 z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
savedPasswords: {
|
savedPasswords: {
|
||||||
type: OptionType.STRING,
|
type: OptionType.STRING,
|
||||||
|
|
@ -149,6 +155,11 @@ export default definePlugin({
|
||||||
reporterTestable: ReporterTestable.Patches,
|
reporterTestable: ReporterTestable.Patches,
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
|
chatBarButton: {
|
||||||
|
icon: ChatBarIcon,
|
||||||
|
render: ChatBarRender
|
||||||
|
},
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
// Indicator
|
// Indicator
|
||||||
|
|
@ -165,7 +176,6 @@ export default definePlugin({
|
||||||
const { default: StegCloak } = await getStegCloak();
|
const { default: StegCloak } = await getStegCloak();
|
||||||
steggo = new StegCloak(true, false);
|
steggo = new StegCloak(true, false);
|
||||||
},
|
},
|
||||||
renderChatBarButton: ChatBarIcon,
|
|
||||||
messagePopoverButton: {
|
messagePopoverButton: {
|
||||||
icon: PopOverIcon,
|
icon: PopOverIcon,
|
||||||
render(message) {
|
render(message) {
|
||||||
|
|
|
||||||
|
|
@ -72,14 +72,7 @@ const FetchTimeButton: ChatBarButtonFactory = ({ isMainChat }) => {
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: "4px"
|
gap: "4px"
|
||||||
}}>
|
}}>
|
||||||
<svg
|
{FetchTimeIcon()}
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4M12.5,7V12.25L17,14.92L16.25,16.15L11,13V7H12.5Z" />
|
|
||||||
</svg>
|
|
||||||
<span style={{
|
<span style={{
|
||||||
fontSize: "12px",
|
fontSize: "12px",
|
||||||
color: iconColor,
|
color: iconColor,
|
||||||
|
|
@ -92,6 +85,19 @@ const FetchTimeButton: ChatBarButtonFactory = ({ isMainChat }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function FetchTimeIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
>
|
||||||
|
<path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4M12.5,7V12.25L17,14.92L16.25,16.15L11,13V7H12.5Z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function formatTimeAgo(timestamp: Date): string {
|
function formatTimeAgo(timestamp: Date): string {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const diff = now.getTime() - timestamp.getTime();
|
const diff = now.getTime() - timestamp.getTime();
|
||||||
|
|
@ -145,6 +151,11 @@ export default definePlugin({
|
||||||
authors: [EquicordDevs.GroupXyz],
|
authors: [EquicordDevs.GroupXyz],
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
|
chatBarButton: {
|
||||||
|
icon: FetchTimeIcon,
|
||||||
|
render: FetchTimeButton
|
||||||
|
},
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
FluxDispatcher.subscribe("CHANNEL_SELECT", handleChannelSelect);
|
FluxDispatcher.subscribe("CHANNEL_SELECT", handleChannelSelect);
|
||||||
FluxDispatcher.subscribe("LOAD_MESSAGES_SUCCESS", handleMessageLoad);
|
FluxDispatcher.subscribe("LOAD_MESSAGES_SUCCESS", handleMessageLoad);
|
||||||
|
|
@ -164,7 +175,5 @@ export default definePlugin({
|
||||||
currentFetch = null;
|
currentFetch = null;
|
||||||
channelTimings.clear();
|
channelTimings.clear();
|
||||||
currentChannelId = null;
|
currentChannelId = null;
|
||||||
},
|
}
|
||||||
|
|
||||||
renderChatBarButton: FetchTimeButton,
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -21,28 +21,7 @@ import { findComponentByCodeLazy } from "@webpack";
|
||||||
import { openLogModal } from "./LogsModal";
|
import { openLogModal } from "./LogsModal";
|
||||||
|
|
||||||
const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"');
|
const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"');
|
||||||
|
const Icon = findComponentByCodeLazy("0-1.27-.97l-2.5.7a3");
|
||||||
export function OpenLogsIcon() {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
stroke="currentColor"
|
|
||||||
fill="none"
|
|
||||||
strokeWidth="0"
|
|
||||||
viewBox="0 0 15 15"
|
|
||||||
height={24}
|
|
||||||
width={24}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
clipRule="evenodd"
|
|
||||||
fill="currentColor"
|
|
||||||
d="M3 2.5C3 2.22386 3.22386 2 3.5 2H9.08579C9.21839 2 9.34557 2.05268 9.43934 2.14645L11.8536 4.56066C11.9473 4.65443 12 4.78161 12 4.91421V12.5C12 12.7761 11.7761 13 11.5 13H3.5C3.22386 13 3 12.7761 3 12.5V2.5ZM3.5 1C2.67157 1 2 1.67157 2 2.5V12.5C2 13.3284 2.67157 14 3.5 14H11.5C12.3284 14 13 13.3284 13 12.5V4.91421C13 4.51639 12.842 4.13486 12.5607 3.85355L10.1464 1.43934C9.86514 1.15804 9.48361 1 9.08579 1H3.5ZM4.5 4C4.22386 4 4 4.22386 4 4.5C4 4.77614 4.22386 5 4.5 5H7.5C7.77614 5 8 4.77614 8 4.5C8 4.22386 7.77614 4 7.5 4H4.5ZM4.5 7C4.22386 7 4 7.22386 4 7.5C4 7.77614 4.22386 8 4.5 8H10.5C10.7761 8 11 7.77614 11 7.5C11 7.22386 10.7761 7 10.5 7H4.5ZM4.5 10C4.22386 10 4 10.2239 4 10.5C4 10.7761 4.22386 11 4.5 11H10.5C10.7761 11 11 10.7761 11 10.5C11 10.2239 10.7761 10 10.5 10H4.5Z"
|
|
||||||
>
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OpenLogsButton() {
|
export function OpenLogsButton() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -50,7 +29,7 @@ export function OpenLogsButton() {
|
||||||
className="vc-log-toolbox-btn"
|
className="vc-log-toolbox-btn"
|
||||||
onClick={() => openLogModal()}
|
onClick={() => openLogModal()}
|
||||||
tooltip={"Open Logs"}
|
tooltip={"Open Logs"}
|
||||||
icon={OpenLogsIcon}
|
icon={Icon}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,11 @@ export const Native = getNative();
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByPropsLazy } from "@webpack";
|
import { findByPropsLazy } from "@webpack";
|
||||||
import { FluxDispatcher, MessageStore, React, UserStore } from "@webpack/common";
|
import { FluxDispatcher, MessageStore, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
import { OpenLogsButton } from "./components/LogsButton";
|
import { OpenLogsButton } from "./components/LogsButton";
|
||||||
import { openLogModal } from "./components/LogsModal";
|
import { openLogModal } from "./components/LogsModal";
|
||||||
|
|
@ -256,15 +255,6 @@ export default definePlugin({
|
||||||
replace: "deleted:$self.getDeleted(...arguments), editHistory:$self.getEdited(...arguments),"
|
replace: "deleted:$self.getDeleted(...arguments), editHistory:$self.getEdited(...arguments),"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
find: ".controlButtonWrapper,",
|
|
||||||
predicate: () => settings.store.ShowLogsButton,
|
|
||||||
replacement: {
|
|
||||||
match: /(function \i\(\i\){)(.{1,200}toolbar.{1,100}mobileToolbar)/,
|
|
||||||
replace: "$1$self.addIconToToolBar(arguments[0]);$2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
find: "childrenMessageContent:null",
|
find: "childrenMessageContent:null",
|
||||||
replacement: {
|
replacement: {
|
||||||
|
|
@ -310,21 +300,9 @@ export default definePlugin({
|
||||||
openLogModal();
|
openLogModal();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
renderHeaderBarButton() {
|
||||||
addIconToToolBar(e: { toolbar: React.ReactNode[] | React.ReactNode; }) {
|
if (!settings.store.ShowLogsButton) return null;
|
||||||
if (Array.isArray(e.toolbar))
|
return OpenLogsButton();
|
||||||
return e.toolbar.unshift(
|
|
||||||
<ErrorBoundary noop={true}>
|
|
||||||
<OpenLogsButton />
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
|
||||||
|
|
||||||
e.toolbar = [
|
|
||||||
<ErrorBoundary noop={true} key={"MessageLoggerEnhanced"} >
|
|
||||||
<OpenLogsButton />
|
|
||||||
</ErrorBoundary>,
|
|
||||||
e.toolbar,
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
processMessageFetch,
|
processMessageFetch,
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,12 @@ export default definePlugin({
|
||||||
find: ".gifts)",
|
find: ".gifts)",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /(?<="submit"\)\}\);)(?=.{0,50}null!=(\i))/,
|
match: /(?<=(,!\i&&\(null==\(\i=\i\.stickers\)\?void 0.*?\i\.push\(\{).{0,15}node:(.{0,45})},"sticker"\)\}\))/,
|
||||||
replace: '$1["stickers+"]=3;'
|
replace: "$1key:\"stickers+\",node:$2,stickersType:\"stickers+\"},\"stickers+\")})"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /(?<=,.{0,5}\(null==\(\i=\i\.stickers\)\?void 0.*?(\i)\.push\(\{.{0,15}node:(.{0,15}{disabled:\i,type:\i)},"sticker"\)\}\))/,
|
match: /(?<="submit"\)\}\);)(?=.{0,50}null!=(\i))/,
|
||||||
replace: ",arguments[0].type?.submit?.button&&$1.push({key:\"stickers+\",node:$2,stickersType:\"stickers+\"},\"stickers+\")})"
|
replace: '$1["stickers+"]=3;'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ export default definePlugin({
|
||||||
name: "MoreUserTags",
|
name: "MoreUserTags",
|
||||||
description: "Adds tags for webhooks and moderative roles (owner, admin, etc.)",
|
description: "Adds tags for webhooks and moderative roles (owner, admin, etc.)",
|
||||||
authors: [Devs.Cyn, Devs.TheSun, Devs.RyanCaoDev, Devs.LordElias, Devs.AutumnVN, EquicordDevs.Hen],
|
authors: [Devs.Cyn, Devs.TheSun, Devs.RyanCaoDev, Devs.LordElias, Devs.AutumnVN, EquicordDevs.Hen],
|
||||||
dependencies: ["MemberListDecoratorsAPI", "NicknameIconsAPI", "MessageDecorationsAPI"],
|
|
||||||
settings,
|
settings,
|
||||||
patches: [
|
patches: [
|
||||||
// Make discord actually use our tags
|
// Make discord actually use our tags
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,7 @@
|
||||||
* 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 "@equicordplugins/_misc/styles.css";
|
import { Alert } from "@components/Alert";
|
||||||
|
|
||||||
import { Paragraph } from "@components/Paragraph";
|
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
|
|
@ -26,11 +24,11 @@ export default definePlugin({
|
||||||
name: "NeverPausePreviews",
|
name: "NeverPausePreviews",
|
||||||
description: "Prevents in-call/PiP previews (screenshare, streams, etc) from pausing even if the client loses focus",
|
description: "Prevents in-call/PiP previews (screenshare, streams, etc) from pausing even if the client loses focus",
|
||||||
authors: [EquicordDevs.vappstar],
|
authors: [EquicordDevs.vappstar],
|
||||||
settingsAboutComponent: () => <>
|
settingsAboutComponent: () => (
|
||||||
<Paragraph className="plugin-warning">
|
<Alert.Warning>
|
||||||
This plugin will cause discord to use more resources than normal
|
This plugin will cause discord to use more resources than normal
|
||||||
</Paragraph>
|
</Alert.Warning>
|
||||||
</>,
|
),
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "streamerPaused()",
|
find: "streamerPaused()",
|
||||||
|
|
|
||||||
23
src/equicordplugins/noAppsAllowed/index.ts
Normal file
23
src/equicordplugins/noAppsAllowed/index.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2023 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { EquicordDevs } from "@utils/constants";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "NoAppsAllowed",
|
||||||
|
description: "returns the bot's tag :skulk:",
|
||||||
|
authors: [EquicordDevs.meowabyte],
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: '"#{intl::APP_TAG::hash}":',
|
||||||
|
replacement: {
|
||||||
|
match: /(#{intl::APP_TAG::hash}":\[").*?("\])/,
|
||||||
|
replace: "$1BOT$2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
@ -4,23 +4,14 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addMessagePreSendListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "NoBulletPoints",
|
name: "NoBulletPoints",
|
||||||
description: "Stops you from typing markdown bullet points (stinky)",
|
description: "Stops you from typing markdown bullet points (stinky)",
|
||||||
authors: [Devs.Samwich],
|
authors: [Devs.Samwich],
|
||||||
dependencies: ["MessageEventsAPI"],
|
onBeforeMessageSend(channelId, msg) {
|
||||||
start() {
|
msg.content = textProcessing(msg.content);
|
||||||
this.preSend = addMessagePreSendListener((channelId, msg) => {
|
|
||||||
msg.content = textProcessing(msg.content);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
stop() {
|
|
||||||
this.preSend = removeMessagePreSendListener((channelId, msg) => {
|
|
||||||
msg.content = textProcessing(msg.content);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,8 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "@equicordplugins/_misc/styles.css";
|
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Paragraph } from "@components/Paragraph";
|
import { Alert } from "@components/Alert";
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { UserStore } from "@webpack/common";
|
import { UserStore } from "@webpack/common";
|
||||||
|
|
@ -51,11 +49,11 @@ export default definePlugin({
|
||||||
name: "PlatformSpoofer",
|
name: "PlatformSpoofer",
|
||||||
description: "Spoof what platform or device you're on",
|
description: "Spoof what platform or device you're on",
|
||||||
authors: [EquicordDevs.Drag],
|
authors: [EquicordDevs.Drag],
|
||||||
settingsAboutComponent: () => <>
|
settingsAboutComponent: () => (
|
||||||
<Paragraph className="plugin-warning">
|
<Alert.Warning>
|
||||||
We can't guarantee this plugin won't get you warned or banned.
|
We can't guarantee this plugin won't get you warned or banned.
|
||||||
</Paragraph>
|
</Alert.Warning>
|
||||||
</>,
|
),
|
||||||
settings: settings,
|
settings: settings,
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addMessagePreSendListener,
|
|
||||||
MessageSendListener,
|
MessageSendListener,
|
||||||
removeMessagePreSendListener,
|
|
||||||
} from "@api/MessageEvents";
|
} from "@api/MessageEvents";
|
||||||
import {
|
import {
|
||||||
definePluginSettings,
|
definePluginSettings,
|
||||||
|
|
@ -67,9 +65,7 @@ export default definePlugin({
|
||||||
name: "PolishWording",
|
name: "PolishWording",
|
||||||
description: "Tweaks your messages to make them look nicer and have better grammar. See settings",
|
description: "Tweaks your messages to make them look nicer and have better grammar. See settings",
|
||||||
authors: [Devs.Samwich, EquicordDevs.WKoA],
|
authors: [Devs.Samwich, EquicordDevs.WKoA],
|
||||||
dependencies: ["MessageEventsAPI"],
|
onBeforeMessageSend: presendObject,
|
||||||
start: () => addMessagePreSendListener(presendObject),
|
|
||||||
stop: () => removeMessagePreSendListener(presendObject),
|
|
||||||
settings,
|
settings,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,15 @@
|
||||||
* 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 "@equicordplugins/_misc/styles.css";
|
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
import { showNotification } from "@api/Notifications";
|
import { showNotification } from "@api/Notifications";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { ErrorBoundary } from "@components/index";
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { getTheme, Theme } from "@utils/discord";
|
import { getTheme, Theme } from "@utils/discord";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
||||||
import { Button, ChannelStore, FluxDispatcher, GuildChannelStore, NavigationRouter, RestAPI, Tooltip, UserStore } from "@webpack/common";
|
import { ChannelStore, FluxDispatcher, GuildChannelStore, NavigationRouter, RestAPI, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
const QuestIcon = findComponentByCodeLazy("10.47a.76.76");
|
const QuestIcon = findComponentByCodeLazy("10.47a.76.76");
|
||||||
const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"');
|
const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"');
|
||||||
|
|
@ -38,16 +36,13 @@ let questIdCheck = 0;
|
||||||
|
|
||||||
function ToolBarHeader() {
|
function ToolBarHeader() {
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary noop={true}>
|
<HeaderBarIcon
|
||||||
<HeaderBarIcon
|
tooltip="Complete Quest"
|
||||||
tooltip="Complete Quest"
|
position="bottom"
|
||||||
position="bottom"
|
className="vc-quest-completer"
|
||||||
className="vc-quest-completer"
|
icon={QuestIcon}
|
||||||
icon={QuestIcon}
|
onClick={openCompleteQuestUI}
|
||||||
onClick={openCompleteQuestUI}
|
/>
|
||||||
>
|
|
||||||
</HeaderBarIcon>
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,11 +208,6 @@ async function openCompleteQuestUI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
useNavBar: {
|
|
||||||
description: "Move quest button down to the server nav bar",
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
disableNotifications: {
|
disableNotifications: {
|
||||||
description: "Disable notifications when no quests are available or when a quest is completed",
|
description: "Disable notifications when no quests are available or when a quest is completed",
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
|
|
@ -238,22 +228,6 @@ export default definePlugin({
|
||||||
replace: "onClick:()=>$self.mobileQuestPatch($1)"
|
replace: "onClick:()=>$self.mobileQuestPatch($1)"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
find: '?"BACK_FORWARD_NAVIGATION":',
|
|
||||||
replacement: {
|
|
||||||
match: /"HELP".{0,100}className:\i\}\)(?=\])/,
|
|
||||||
replace: "$&,$self.renderTitleBar()"
|
|
||||||
},
|
|
||||||
predicate: () => !settings.store.useNavBar
|
|
||||||
},
|
|
||||||
{
|
|
||||||
find: ".controlButtonWrapper,",
|
|
||||||
replacement: {
|
|
||||||
match: /(function \i\(\i\){)(.{1,200}toolbar.{1,200}mobileToolbar)/,
|
|
||||||
replace: "$1$self.renderNavBar(arguments[0]);$2"
|
|
||||||
},
|
|
||||||
predicate: () => settings.store.useNavBar
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
mobileQuestPatch(questId) {
|
mobileQuestPatch(questId) {
|
||||||
if (questId === questIdCheck) return;
|
if (questId === questIdCheck) return;
|
||||||
|
|
@ -265,37 +239,5 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
renderTitleBar() {
|
renderHeaderBarButton: ToolBarHeader
|
||||||
return (
|
|
||||||
<ErrorBoundary noop>
|
|
||||||
<Tooltip text="Complete Quest">
|
|
||||||
{tooltipProps => (
|
|
||||||
<Button style={{ backgroundColor: "transparent", border: "none" }}
|
|
||||||
{...tooltipProps}
|
|
||||||
size={Button.Sizes.SMALL}
|
|
||||||
className={"vc-quest-completer-icon"}
|
|
||||||
onClick={openCompleteQuestUI}
|
|
||||||
>
|
|
||||||
<QuestIcon width={20} height={20} />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Tooltip>
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
renderNavBar(e) {
|
|
||||||
if (Array.isArray(e.toolbar))
|
|
||||||
return e.toolbar.unshift(
|
|
||||||
<ErrorBoundary noop={true}>
|
|
||||||
<ToolBarHeader />
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
|
||||||
|
|
||||||
e.toolbar = [
|
|
||||||
<ErrorBoundary noop={true} key={"QuestCompleter"}>
|
|
||||||
<ToolBarHeader />
|
|
||||||
</ErrorBoundary>,
|
|
||||||
e.toolbar,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,18 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "@equicordplugins/_misc/styles.css";
|
import { Alert } from "@components/Alert";
|
||||||
|
|
||||||
import { Paragraph } from "@components/Paragraph";
|
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "QuestFocused",
|
name: "QuestFocused",
|
||||||
description: "Prevent the quests player from pausing and possibly skip it all together.",
|
description: "Prevent the quests player from pausing and possibly skip it all together.",
|
||||||
settingsAboutComponent: () => <>
|
settingsAboutComponent: () => (
|
||||||
<Paragraph className="plugin-warning">
|
<Alert.Warning>
|
||||||
You might need to spam left mouse button on the video to skip it.
|
You might need to spam left mouse button on the video to skip it.
|
||||||
</Paragraph>
|
</Alert.Warning>
|
||||||
</>,
|
),
|
||||||
authors: [EquicordDevs.secp192k1],
|
authors: [EquicordDevs.secp192k1],
|
||||||
patches: [
|
patches: [
|
||||||
// Block pausing
|
// Block pausing
|
||||||
|
|
|
||||||
|
|
@ -1073,7 +1073,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Adds a maxDigits prop to the LowerBadge component which allows for not truncating, or for truncating at a specific threshold.
|
// Adds a maxDigits prop to the LowerBadge component which allows for not truncating, or for truncating at a specific threshold.
|
||||||
find: "STATUS_DANGER,disableColor",
|
find: '"renderBadgeCount"])',
|
||||||
group: true,
|
group: true,
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
|
|
@ -1251,7 +1251,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Add the trigger to the memo for rerendering the progress label.
|
// Add the trigger to the memo for rerendering the progress label.
|
||||||
match: /(\i.intl.string\(\i.\i#{intl::QUESTS_SEE_CODE}\)}\)}},\[)/,
|
match: /(\i\.intl\.string\(\i\.\i#{intl::QUESTS_SEE_CODE}\)\}\)\}\},\[|\)\}\}\},\[)/,
|
||||||
replace: "$1questRerenderTrigger,"
|
replace: "$1questRerenderTrigger,"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import { formatLowerBadge } from "./misc";
|
||||||
// GuildlessServerListItem's built-in pill does not support unread state.
|
// GuildlessServerListItem's built-in pill does not support unread state.
|
||||||
export const GuildlessServerListItemComponent = findComponentByCodeLazy("tooltip:", "lowerBadgeSize:");
|
export const GuildlessServerListItemComponent = findComponentByCodeLazy("tooltip:", "lowerBadgeSize:");
|
||||||
export const GuildedServerListItemPillComponent = findComponentByCodeLazy('"pill":"empty"');
|
export const GuildedServerListItemPillComponent = findComponentByCodeLazy('"pill":"empty"');
|
||||||
export const ServerListItemLowerBadgeComponent = findComponentByCodeLazy("STATUS_DANGER,disableColor:");
|
export const ServerListItemLowerBadgeComponent = findComponentByCodeLazy("numberBadge", '"renderBadgeCount"');
|
||||||
export const ServerListItemUpperBadgeComponent = findComponentByCodeLazy("STATUS_DANGER,shape:", "iconBadge,");
|
export const ServerListItemUpperBadgeComponent = findComponentByCodeLazy("iconBadge", ".ROUND,disableColor");
|
||||||
export const RadioGroup = findComponentByCodeLazy(',["label","description"');
|
export const RadioGroup = findComponentByCodeLazy(',["label","description"');
|
||||||
export const QuestTile = findComponentByCodeLazy(".rowIndex,trackGuildAndChannelMetadata");
|
export const QuestTile = findComponentByCodeLazy(".rowIndex,trackGuildAndChannelMetadata");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,11 @@ export default definePlugin({
|
||||||
name: "SekaiStickers",
|
name: "SekaiStickers",
|
||||||
description: "Sekai Stickers built in discord originally from github.com/TheOriginalAyaka",
|
description: "Sekai Stickers built in discord originally from github.com/TheOriginalAyaka",
|
||||||
authors: [Devs.MaiKokain],
|
authors: [Devs.MaiKokain],
|
||||||
dependencies: ["ChatInputButtonAPI"],
|
|
||||||
settings,
|
settings,
|
||||||
renderChatBarButton: SekaiStickerChatButton,
|
chatBarButton: {
|
||||||
|
icon: kanadeSvg,
|
||||||
|
render: SekaiStickerChatButton
|
||||||
|
},
|
||||||
async start() {
|
async start() {
|
||||||
const fonts = [{ name: "YurukaStd", url: "https://raw.githubusercontent.com/TheOriginalAyaka/sekai-stickers/47a2ca33b8cb35f59800e8faad48980e4ce5ea71/src/fonts/YurukaStd.woff2" }, { name: "SSFangTangTi", url: "https://raw.githubusercontent.com/TheOriginalAyaka/sekai-stickers/main/src/fonts/ShangShouFangTangTi.woff2" }];
|
const fonts = [{ name: "YurukaStd", url: "https://raw.githubusercontent.com/TheOriginalAyaka/sekai-stickers/47a2ca33b8cb35f59800e8faad48980e4ce5ea71/src/fonts/YurukaStd.woff2" }, { name: "SSFangTangTi", url: "https://raw.githubusercontent.com/TheOriginalAyaka/sekai-stickers/main/src/fonts/ShangShouFangTangTi.woff2" }];
|
||||||
if (!IS_FONTS_LOADED) {
|
if (!IS_FONTS_LOADED) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addMessageDecoration, removeMessageDecoration } from "@api/MessageDecorations";
|
|
||||||
import { Devs, EquicordDevs } from "@utils/constants";
|
import { Devs, EquicordDevs } from "@utils/constants";
|
||||||
import { isEquicordPluginDev, isPluginDev } from "@utils/misc";
|
import { isEquicordPluginDev, isPluginDev } from "@utils/misc";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
|
@ -142,12 +141,8 @@ export default definePlugin({
|
||||||
name: "ShowBadgesInChat",
|
name: "ShowBadgesInChat",
|
||||||
authors: [Devs.Inbestigator, EquicordDevs.KrystalSkull],
|
authors: [Devs.Inbestigator, EquicordDevs.KrystalSkull],
|
||||||
description: "Shows the message author's badges beside their name in chat.",
|
description: "Shows the message author's badges beside their name in chat.",
|
||||||
dependencies: ["MessageDecorationsAPI"],
|
|
||||||
settings,
|
settings,
|
||||||
start: () => {
|
renderMessageDecoration(props) {
|
||||||
addMessageDecoration("vc-show-badges-in-chat", props => props.message?.author ? <ChatBadges author={props.message.author} /> : null);
|
return props.message?.author ? <ChatBadges author={props.message.author} /> : null;
|
||||||
},
|
|
||||||
stop: () => {
|
|
||||||
removeMessageDecoration("vc-show-badges-in-chat");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,15 @@ export default definePlugin({
|
||||||
name: "ShowResourceChannels",
|
name: "ShowResourceChannels",
|
||||||
description: "shows the channels hidden behind the server resources in the channel list",
|
description: "shows the channels hidden behind the server resources in the channel list",
|
||||||
authors: [EquicordDevs.VillainsRule],
|
authors: [EquicordDevs.VillainsRule],
|
||||||
patches: [{
|
patches: [
|
||||||
find: '"should_show_in_recents"',
|
{
|
||||||
replacement: [{
|
find: ".GUILD_DIRECTORY:null",
|
||||||
match: /\i\.hideResourceChannels&&/,
|
replacement: [
|
||||||
replace: "false&&"
|
{
|
||||||
}]
|
match: /\i\.hideResourceChannels&&/,
|
||||||
}]
|
replace: "false&&"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
import { ChatBarButton, ChatBarButtonFactory } from "@api/ChatButtons";
|
import { ChatBarButton, ChatBarButtonFactory } from "@api/ChatButtons";
|
||||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands";
|
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands";
|
||||||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { addMessagePreSendListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs, EquicordDevs } from "@utils/constants";
|
import { Devs, EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
|
@ -70,13 +69,13 @@ const SignatureToggle: ChatBarButtonFactory = ({ isMainChat }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMessage = ((channelId, msg) => {
|
function SignatureIcon() {
|
||||||
if (!settings.store.isEnabled) {
|
return (
|
||||||
msg.content = msg.content;
|
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 21.333">
|
||||||
} else {
|
<path fill="currentColor" d="M2 4.621a.5.5 0 0 1 .854-.353l6.01 6.01c.126.126.17.31.15.487a2 2 0 1 0 1.751-1.751a.59.59 0 0 1-.487-.15l-6.01-6.01A.5.5 0 0 1 4.62 2H11a9 9 0 0 1 8.468 12.054l2.24 2.239a1 1 0 0 1 0 1.414l-4 4a1 1 0 0 1-1.415 0l-2.239-2.239A9 9 0 0 1 2 11z" />
|
||||||
msg.content = textProcessing(msg.content);
|
</svg>
|
||||||
}
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
const ChatBarContextCheckbox: NavContextMenuPatchCallback = children => {
|
const ChatBarContextCheckbox: NavContextMenuPatchCallback = children => {
|
||||||
const { isEnabled, contextMenu } = settings.use(["isEnabled", "contextMenu"]);
|
const { isEnabled, contextMenu } = settings.use(["isEnabled", "contextMenu"]);
|
||||||
|
|
@ -102,17 +101,23 @@ export default definePlugin({
|
||||||
name: "Signature",
|
name: "Signature",
|
||||||
description: "Automated fingerprint/end text",
|
description: "Automated fingerprint/end text",
|
||||||
authors: [Devs.Ven, Devs.Rini, Devs.ImBanana, EquicordDevs.KrystalSkull],
|
authors: [Devs.Ven, Devs.Rini, Devs.ImBanana, EquicordDevs.KrystalSkull],
|
||||||
dependencies: ["MessageEventsAPI", "ChatInputButtonAPI"],
|
onBeforeMessageSend(channelId, msg) {
|
||||||
renderChatBarButton: SignatureToggle,
|
if (!settings.store.isEnabled) {
|
||||||
|
msg.content = msg.content;
|
||||||
|
} else {
|
||||||
|
msg.content = textProcessing(msg.content);
|
||||||
|
}
|
||||||
|
},
|
||||||
start: () => {
|
start: () => {
|
||||||
if (settings.store.isEnabled) true;
|
if (settings.store.isEnabled) true;
|
||||||
addMessagePreSendListener(handleMessage);
|
|
||||||
},
|
},
|
||||||
stop: () => {
|
stop: () => {
|
||||||
if (settings.store.isEnabled) false;
|
if (settings.store.isEnabled) false;
|
||||||
removeMessagePreSendListener(handleMessage);
|
},
|
||||||
|
|
||||||
|
chatBarButton: {
|
||||||
|
icon: SignatureIcon,
|
||||||
|
render: SignatureToggle
|
||||||
},
|
},
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
import { AudioPlayerInterface, createAudioPlayer } from "@api/AudioPlayer";
|
import { AudioPlayerInterface, createAudioPlayer } from "@api/AudioPlayer";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import { ModalProps, ModalRoot, openModal } from "@utils/modal";
|
import { ModalProps, ModalRoot, openModal } from "@utils/modal";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
|
@ -143,15 +142,7 @@ export default definePlugin({
|
||||||
authors: [EquicordDevs.sliwka],
|
authors: [EquicordDevs.sliwka],
|
||||||
settings,
|
settings,
|
||||||
dependencies: ["AudioPlayerAPI"],
|
dependencies: ["AudioPlayerAPI"],
|
||||||
patches: [
|
renderHeaderBarButton: SoggyButton,
|
||||||
{
|
|
||||||
find: ".controlButtonWrapper,",
|
|
||||||
replacement: {
|
|
||||||
match: /(function \i\(\i\){)(.{1,200}toolbar.{1,450}mobileToolbar)/,
|
|
||||||
replace: "$1$self.addIconToToolBar(arguments[0]);$2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
assignBoop(settings.store.boopLink, settings.store.boopVolume * 100);
|
assignBoop(settings.store.boopLink, settings.store.boopVolume * 100);
|
||||||
|
|
@ -162,21 +153,4 @@ export default definePlugin({
|
||||||
boopSound?.delete();
|
boopSound?.delete();
|
||||||
song?.delete();
|
song?.delete();
|
||||||
},
|
},
|
||||||
|
|
||||||
// taken from message logger lol
|
|
||||||
addIconToToolBar(e: { toolbar: React.ReactNode[] | React.ReactNode; }) {
|
|
||||||
if (Array.isArray(e.toolbar))
|
|
||||||
return e.toolbar.unshift(
|
|
||||||
<ErrorBoundary noop={true}>
|
|
||||||
<SoggyButton />
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
|
||||||
|
|
||||||
e.toolbar = [
|
|
||||||
<ErrorBoundary noop={true} key={"MessageLoggerEnhanced"} >
|
|
||||||
<SoggyButton />
|
|
||||||
</ErrorBoundary>,
|
|
||||||
e.toolbar,
|
|
||||||
];
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,11 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
|
||||||
import { disableStyle, enableStyle } from "@api/Styles";
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Devs, EquicordDevs } from "@utils/constants";
|
import { Devs, EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { FluxDispatcher } from "@webpack/common";
|
import { FluxDispatcher } from "@webpack/common";
|
||||||
|
|
||||||
import { CharBarButton, ChatBarIcon } from "./components/Icons";
|
|
||||||
import { OpenSBLogsButton } from "./components/SoundBoardLog";
|
import { OpenSBLogsButton } from "./components/SoundBoardLog";
|
||||||
import settings from "./settings";
|
import settings from "./settings";
|
||||||
import { updateLoggedSounds } from "./store";
|
import { updateLoggedSounds } from "./store";
|
||||||
|
|
@ -22,33 +19,9 @@ export default definePlugin({
|
||||||
name: "SoundBoardLogger",
|
name: "SoundBoardLogger",
|
||||||
authors: [Devs.Moxxie, EquicordDevs.Fres, Devs.amy, Devs.thororen],
|
authors: [Devs.Moxxie, EquicordDevs.Fres, Devs.amy, Devs.thororen],
|
||||||
description: "Logs all soundboards that are played in a voice chat and allows you to download them",
|
description: "Logs all soundboards that are played in a voice chat and allows you to download them",
|
||||||
dependencies: ["AudioPlayerAPI", "ChatInputButtonAPI"],
|
dependencies: ["AudioPlayerAPI"],
|
||||||
patches: [
|
|
||||||
{
|
|
||||||
predicate: () => settings.store.IconLocation === "toolbar",
|
|
||||||
find: ".controlButtonWrapper,",
|
|
||||||
replacement: {
|
|
||||||
match: /(function \i\(\i\){)(.{1,500}toolbar.{1,500}mobileToolbar)/,
|
|
||||||
replace: "$1$self.addSBIconToToolBar(arguments[0]);$2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
settings,
|
settings,
|
||||||
addSBIconToToolBar(e: { toolbar: React.ReactNode[] | React.ReactNode; }) {
|
renderHeaderBarButton: OpenSBLogsButton,
|
||||||
if (Array.isArray(e.toolbar))
|
|
||||||
return e.toolbar.unshift(
|
|
||||||
<ErrorBoundary noop={true}>
|
|
||||||
<OpenSBLogsButton />
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
|
||||||
|
|
||||||
e.toolbar = [
|
|
||||||
<ErrorBoundary noop={true} key={"SoundBoardLogger"} >
|
|
||||||
<OpenSBLogsButton />
|
|
||||||
</ErrorBoundary>,
|
|
||||||
e.toolbar,
|
|
||||||
];
|
|
||||||
},
|
|
||||||
start() {
|
start() {
|
||||||
enableStyle(styles);
|
enableStyle(styles);
|
||||||
FluxDispatcher.subscribe("VOICE_CHANNEL_EFFECT_SEND", async sound => {
|
FluxDispatcher.subscribe("VOICE_CHANNEL_EFFECT_SEND", async sound => {
|
||||||
|
|
@ -56,10 +29,8 @@ export default definePlugin({
|
||||||
await updateLoggedSounds(sound);
|
await updateLoggedSounds(sound);
|
||||||
getListeners().forEach(cb => cb());
|
getListeners().forEach(cb => cb());
|
||||||
});
|
});
|
||||||
if (settings.store.IconLocation === "chat") addChatBarButton("vc-soundlog-button", CharBarButton, ChatBarIcon);
|
|
||||||
},
|
},
|
||||||
stop() {
|
stop() {
|
||||||
disableStyle(styles);
|
disableStyle(styles);
|
||||||
if (settings.store.IconLocation === "chat") removeChatBarButton("vc-soundlog-button");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -85,15 +85,6 @@ const settings = definePluginSettings({
|
||||||
default: 0.5,
|
default: 0.5,
|
||||||
markers: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
|
markers: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
|
||||||
},
|
},
|
||||||
IconLocation: {
|
|
||||||
description: "choose where to show the SoundBoard Log icon (requires restart)",
|
|
||||||
type: OptionType.SELECT,
|
|
||||||
options: [
|
|
||||||
{ label: "Toolbar", value: "toolbar", default: true },
|
|
||||||
{ label: "Chat input", value: "chat" }
|
|
||||||
],
|
|
||||||
restartNeeded: true
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default settings;
|
export default settings;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addMessagePreSendListener, MessageSendListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
import { MessageSendListener } from "@api/MessageEvents";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import { getCurrentChannel, sendMessage } from "@utils/discord";
|
import { getCurrentChannel, sendMessage } from "@utils/discord";
|
||||||
|
|
@ -117,16 +117,11 @@ export default definePlugin({
|
||||||
name: "SplitLargeMessages",
|
name: "SplitLargeMessages",
|
||||||
description: "Splits large messages into multiple to fit Discord's message limit.",
|
description: "Splits large messages into multiple to fit Discord's message limit.",
|
||||||
authors: [EquicordDevs.Reycko],
|
authors: [EquicordDevs.Reycko],
|
||||||
dependencies: ["MessageEventsAPI"],
|
|
||||||
settings,
|
settings,
|
||||||
|
onBeforeMessageSend: listener,
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
if (settings.store.maxLength === 0) maxLength = autoMaxLength();
|
if (settings.store.maxLength === 0) maxLength = autoMaxLength();
|
||||||
addMessagePreSendListener(listener);
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeMessagePreSendListener(listener);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,21 @@ const ReverseMessageToggle: ChatBarButtonFactory = ({ isMainChat }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function ReverseMessageIcon() {
|
||||||
|
return (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20">
|
||||||
|
<path fill={"currentColor"} d="M482-160q-134 0-228-93t-94-227v-7l-36 36q-11 11-28 11t-28-11q-11-11-11-28t11-28l104-104q12-12 28-12t28 12l104 104q11 11 11 28t-11 28q-11 11-28 11t-28-11l-36-36v7q0 100 70.5 170T482-240q16 0 31.5-2t30.5-7q17-5 32 1t23 21q8 16 1.5 31.5T577-175q-23 8-47 11.5t-48 3.5Zm-4-560q-16 0-31.5 2t-30.5 7q-17 5-32.5-1T360-733q-8-15-1.5-30.5T381-784q24-8 48-12t49-4q134 0 228 93t94 227v7l36-36q11-11 28-11t28 11q11 11 11 28t-11 28L788-349q-12 12-28 12t-28-12L628-453q-11-11-11-28t11-28q11-11 28-11t28 11l36 36v-7q0-100-70.5-170T478-720Z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "TalkInReverse",
|
name: "TalkInReverse",
|
||||||
authors: [EquicordDevs.Tolgchu],
|
authors: [EquicordDevs.Tolgchu],
|
||||||
description: "Reverses the message content before sending it.",
|
description: "Reverses the message content before sending it.",
|
||||||
dependencies: ["MessageEventsAPI", "ChatInputButtonAPI"],
|
dependencies: ["MessageEventsAPI"],
|
||||||
renderChatBarButton: ReverseMessageToggle,
|
chatBarButton: {
|
||||||
|
icon: ReverseMessageIcon,
|
||||||
|
render: ReverseMessageToggle
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ const messageCtxPatch: NavContextMenuPatchCallback = (children, { message }) =>
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "Translate+",
|
name: "Translate+",
|
||||||
description: "Vencord's translate plugin but with support for artistic languages!",
|
description: "Vencord's translate plugin but with support for artistic languages!",
|
||||||
dependencies: ["MessageAccessoriesAPI"],
|
|
||||||
authors: [Devs.Ven, EquicordDevs.Prince527],
|
authors: [Devs.Ven, EquicordDevs.Prince527],
|
||||||
settings,
|
settings,
|
||||||
contextMenus: {
|
contextMenus: {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Paragraph } from "@components/Paragraph";
|
import { Alert } from "@components/Alert";
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { User } from "@vencord/discord-types";
|
import { User } from "@vencord/discord-types";
|
||||||
|
|
@ -41,9 +41,9 @@ export default definePlugin({
|
||||||
description: "Mention any user, regardless of channel access.",
|
description: "Mention any user, regardless of channel access.",
|
||||||
settings,
|
settings,
|
||||||
settingsAboutComponent: () => (
|
settingsAboutComponent: () => (
|
||||||
<Paragraph className="plugin-warning">
|
<Alert.Warning>
|
||||||
Using Global Mention can cause performance issues and show an absurd amount of users in the autocomplete.
|
Using Global Mention can cause performance issues and show an absurd amount of users in the autocomplete.
|
||||||
</Paragraph>
|
</Alert.Warning>
|
||||||
),
|
),
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { ReadStateStore, useStateFromStores } from "@webpack/common";
|
||||||
|
|
||||||
const UserGuildSettingsStore = findStoreLazy("UserGuildSettingsStore");
|
const UserGuildSettingsStore = findStoreLazy("UserGuildSettingsStore");
|
||||||
const JoinedThreadsStore = findStoreLazy("JoinedThreadsStore");
|
const JoinedThreadsStore = findStoreLazy("JoinedThreadsStore");
|
||||||
const NumberBadge = findComponentByCodeLazy("numberBadge", ".STATUS_DANGER,");
|
const NumberBadge = findComponentByCodeLazy("numberBadge", '"renderBadgeCount"');
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
showOnMutedChannels: {
|
showOnMutedChannels: {
|
||||||
|
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2024 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 { Tooltip, useRef, useState } from "@webpack/common";
|
|
||||||
|
|
||||||
const settings = definePluginSettings(
|
|
||||||
{
|
|
||||||
preservePitch: {
|
|
||||||
type: OptionType.BOOLEAN,
|
|
||||||
description: "Should pitch be preserved when changing speed?",
|
|
||||||
default: false,
|
|
||||||
restartNeeded: true
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default definePlugin({
|
|
||||||
name: "VideoSpeed",
|
|
||||||
description: "Allows you to change the speed of videos",
|
|
||||||
authors: [Devs.Samwich],
|
|
||||||
settings,
|
|
||||||
patches: [
|
|
||||||
{
|
|
||||||
find: /\.VIDEO\?\i\.videoControls:/,
|
|
||||||
replacement: {
|
|
||||||
match: /children:\[this\.renderPlayIcon\(\),.{0,200}\.setDurationRef}\),/,
|
|
||||||
replace: "$&$self.SpeedButton(),"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
SpeedButton: ErrorBoundary.wrap(() => {
|
|
||||||
const elementRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const [speed, setSpeed] = useState(1);
|
|
||||||
|
|
||||||
const speedPaths =
|
|
||||||
{
|
|
||||||
1.5: "M320 48a48 48 0 1 1 96 0a48 48 0 1 1-96 0m-115.5 73.3c-5.4-2.5-11.7-1.9-16.4 1.7l-40.9 30.7c-14.1 10.6-34.2 7.7-44.8-6.4s-7.7-34.2 6.4-44.8l40.9-30.7c23.7-17.8 55.3-21 82.1-8.4l90.4 42.5c29.1 13.7 36.8 51.6 15.2 75.5L299.1 224h97.4c30.3 0 53 27.7 47.1 57.4l-28.2 140.9c-3.5 17.3-20.3 28.6-37.7 25.1s-28.6-20.3-25.1-37.7L377 288h-70.3c8.6 19.6 13.3 41.2 13.3 64c0 88.4-71.6 160-160 160S0 440.4 0 352s71.6-160 160-160c11.1 0 22 1.1 32.4 3.3l54.2-54.2zM160 448a96 96 0 1 0 0-192a96 96 0 1 0 0 192",
|
|
||||||
1.25: "M320 48a48 48 0 1 0-96 0a48 48 0 1 0 96 0M125.7 175.5c9.9-9.9 23.4-15.5 37.5-15.5c1.9 0 3.8.1 5.6.3L137.6 254c-9.3 28 1.7 58.8 26.8 74.5l86.2 53.9l-25.4 88.8c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l28.7-100.4c5.9-20.6-2.6-42.6-20.7-53.9L238 299l30.9-82.4l5.1 12.3c15 35.8 49.9 59.1 88.7 59.1H384c17.7 0 32-14.3 32-32s-14.3-32-32-32h-21.3c-12.9 0-24.6-7.8-29.5-19.7l-6.3-15c-14.6-35.1-44.1-61.9-80.5-73.1l-48.7-15C186.6 97.8 175 96 163.3 96c-31 0-60.8 12.3-82.7 34.3l-23.2 23.1c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l23.1-23.1zM91.2 352H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h69.6c19 0 36.2-11.2 43.9-28.5l11.5-25.9l-9.5-6a95.394 95.394 0 0 1-37.9-44.9z",
|
|
||||||
1: "M112 48a48 48 0 1 1 96 0a48 48 0 1 1-96 0m40 304v128c0 17.7-14.3 32-32 32s-32-14.3-32-32V256.9l-28.6 47.6c-9.1 15.1-28.8 20-43.9 10.9s-20-28.8-10.9-43.9l58.3-97c17.4-28.9 48.6-46.6 82.3-46.6h29.7c33.7 0 64.9 17.7 82.3 46.6l58.3 97c9.1 15.1 4.2 34.8-10.9 43.9s-34.8 4.2-43.9-10.9L232 256.9V480c0 17.7-14.3 32-32 32s-32-14.3-32-32V352z",
|
|
||||||
0.5: "M368 32c41.7 0 75.9 31.8 79.7 72.5l85.6 26.3c25.4 7.8 42.8 31.3 42.8 57.9c0 21.8-11.7 41.9-30.7 52.7l-144.6 82.1l92.5 92.5H544c17.7 0 32 14.3 32 32s-14.3 32-32 32h-64c-8.5 0-16.6-3.4-22.6-9.4L346.9 360.2c11.7-36 3.2-77.1-25.4-105.7c-40.6-40.6-106.3-40.6-146.9-.1l-73.6 70c-6.4 6.1-6.7 16.2-.6 22.6s16.2 6.6 22.6.6l73.8-70.2l.1-.1l.1-.1c3.5-3.5 7.3-6.6 11.3-9.2c27.9-18.5 65.9-15.4 90.5 9.2c24.7 24.7 27.7 62.9 9 90.9c-2.6 3.8-5.6 7.5-9 10.9l-37 37H352c17.7 0 32 14.3 32 32s-14.3 32-32 32H64c-35.3 0-64-28.7-64-64C0 249.6 127 112.9 289.3 97.5C296.2 60.2 328.8 32 368 32m0 104a24 24 0 1 0 0-48a24 24 0 1 0 0 48"
|
|
||||||
};
|
|
||||||
|
|
||||||
return <div ref={elementRef}>
|
|
||||||
<Tooltip text={`Toggle Speed (${speed})`}>
|
|
||||||
{tooltipProps => (
|
|
||||||
<div
|
|
||||||
{...tooltipProps}
|
|
||||||
role="button"
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
paddingTop: "4px",
|
|
||||||
paddingLeft: "4px",
|
|
||||||
paddingRight: "4px",
|
|
||||||
}}
|
|
||||||
onClick={e => {
|
|
||||||
console.log(e);
|
|
||||||
let newSpeed;
|
|
||||||
switch (speed) {
|
|
||||||
case 1:
|
|
||||||
newSpeed = 1.25;
|
|
||||||
break;
|
|
||||||
case 1.25:
|
|
||||||
newSpeed = 1.5;
|
|
||||||
break;
|
|
||||||
case 1.5:
|
|
||||||
newSpeed = 0.5;
|
|
||||||
break;
|
|
||||||
case 0.5:
|
|
||||||
newSpeed = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const parent = e.currentTarget.parentNode!.parentNode!.parentNode!;
|
|
||||||
|
|
||||||
// this works with audio too as it is but it doesnt always select the right audio tag
|
|
||||||
const media = parent.querySelector("video")! /* ?? document.querySelector("source")?.parentElement*/;
|
|
||||||
console.log(media);
|
|
||||||
media.playbackRate = newSpeed;
|
|
||||||
media.preservesPitch = settings.store.preservePitch;
|
|
||||||
setSpeed(newSpeed);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="19px" height="19px" viewBox="0 0 448 512"><path fill="currentColor" d={speedPaths[speed]}></path></svg>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</Tooltip >
|
|
||||||
</div >;
|
|
||||||
}, { noop: true })
|
|
||||||
});
|
|
||||||
|
|
@ -100,7 +100,7 @@ async function loadAllBadges(noCache = false) {
|
||||||
|
|
||||||
let intervalId: any;
|
let intervalId: any;
|
||||||
|
|
||||||
function BadgeContextMenu({ badge }: { badge: ProfileBadge & BadgeUserArgs; }) {
|
export function BadgeContextMenu({ badge }: { badge: ProfileBadge & BadgeUserArgs; }) {
|
||||||
return (
|
return (
|
||||||
<Menu.Menu
|
<Menu.Menu
|
||||||
navId="vc-badge-context"
|
navId="vc-badge-context"
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export function VencordDonorModal() {
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Flex justifyContent="center" style={{ width: "100%" }}>
|
<Flex justifyContent="center" style={{ width: "100%" }}>
|
||||||
<DonateButton link="https://github.com/sponsors/Vendicated" />
|
<DonateButton />
|
||||||
</Flex>
|
</Flex>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</ModalRoot>
|
</ModalRoot>
|
||||||
|
|
@ -113,7 +113,7 @@ export function EquicordDonorModal() {
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Flex justifyContent="center" style={{ width: "100%" }}>
|
<Flex justifyContent="center" style={{ width: "100%" }}>
|
||||||
<DonateButton link="https://github.com/sponsors/thororen1234" />
|
<DonateButton equicord={true} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</ModalRoot>
|
</ModalRoot>
|
||||||
|
|
|
||||||
24
src/plugins/_api/headerBar.ts
Normal file
24
src/plugins/_api/headerBar.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2025 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { EquicordDevs } from "@utils/constants";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "HeaderBarAPI",
|
||||||
|
description: "API to add buttons to the header bar.",
|
||||||
|
authors: [EquicordDevs.Prism],
|
||||||
|
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: '?"BACK_FORWARD_NAVIGATION":',
|
||||||
|
replacement: {
|
||||||
|
match: /(?<=\i\.Fragment,\{children:\[.{1,500}className:\i\}\))(?=\])/,
|
||||||
|
replace: ",...Vencord.Api.HeaderBar._addButtons()"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
@ -4,14 +4,16 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { isPluginEnabled } from "@api/PluginManager";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
import alwaysExpandProfiles from "@equicordplugins/alwaysExpandProfiles";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { getCurrentChannel } from "@utils/discord";
|
import { getCurrentChannel } from "@utils/discord";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { User } from "@vencord/discord-types";
|
import { User } from "@vencord/discord-types";
|
||||||
import { findComponentByCodeLazy } from "@webpack";
|
import { findComponentByCodeLazy } from "@webpack";
|
||||||
import { ContextMenuApi, Menu } from "@webpack/common";
|
import { ContextMenuApi, Menu, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
interface UserProfileProps {
|
interface UserProfileProps {
|
||||||
popoutProps: Record<string, any>;
|
popoutProps: Record<string, any>;
|
||||||
|
|
@ -37,6 +39,10 @@ const AccountPanelContextMenu = ErrorBoundary.wrap(() => {
|
||||||
label={prioritizeServerProfile ? "View Account Profile" : "View Server Profile"}
|
label={prioritizeServerProfile ? "View Account Profile" : "View Server Profile"}
|
||||||
disabled={getCurrentChannel()?.getGuildId() == null}
|
disabled={getCurrentChannel()?.getGuildId() == null}
|
||||||
action={e => {
|
action={e => {
|
||||||
|
if (isPluginEnabled(alwaysExpandProfiles.name)) {
|
||||||
|
const user = UserStore.getCurrentUser();
|
||||||
|
return alwaysExpandProfiles.openUserModal(user);
|
||||||
|
}
|
||||||
openAlternatePopout = true;
|
openAlternatePopout = true;
|
||||||
accountPanelRef.current?.click();
|
accountPanelRef.current?.click();
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -91,21 +91,24 @@ export default definePlugin({
|
||||||
replacement: [
|
replacement: [
|
||||||
// Use Decor avatar decoration hook
|
// Use Decor avatar decoration hook
|
||||||
{
|
{
|
||||||
match: /(?<=\i\)\({avatarDecoration:)(\i)(?=,)(?<=currentUser:(\i).+?)/,
|
match: /(?<=\i\)\({avatarDecoration:)\i(?=,)(?<=currentUser:(\i).+?)/,
|
||||||
replace: "$self.useUserDecorAvatarDecoration($1)??$&"
|
replace: "$self.useUserDecorAvatarDecoration($1)??$&"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// Messages
|
...[
|
||||||
{
|
'"Message Username"', // Messages
|
||||||
find: '"Message Username"',
|
".nameplatePreview,{", // Nameplate preview
|
||||||
|
"#{intl::ayozFl::raw}", // Avatar preview
|
||||||
|
].map(find => ({
|
||||||
|
find,
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /(?<=userValue.{0,25}void 0:)((\i)\.avatarDecoration)/,
|
match: /(?<=userValue.{0,25}void 0:)((\i)\.avatarDecoration)/,
|
||||||
replace: "$self.useUserDecorAvatarDecoration($2)??$1"
|
replace: "$self.useUserDecorAvatarDecoration($2)??$1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
})),
|
||||||
],
|
],
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,5 @@ import { extractAndLoadChunksLazy, findByPropsLazy } from "@webpack";
|
||||||
export const cl = classNameFactory("vc-decor-");
|
export const cl = classNameFactory("vc-decor-");
|
||||||
export const DecorationModalStyles = findByPropsLazy("modalPreview", "modalCloseButton", "spinner", "modal");
|
export const DecorationModalStyles = findByPropsLazy("modalPreview", "modalCloseButton", "spinner", "modal");
|
||||||
|
|
||||||
export const requireAvatarDecorationModal = extractAndLoadChunksLazy(["initialSelectedDecoration:", /initialSelectedDecoration:\i,.{0,300}Promise\.all/]);
|
export const requireAvatarDecorationModal = extractAndLoadChunksLazy(["initialSelectedDecoration:", /initialSelectedDecoration:\i,.{0,300}\i\.e\(/]);
|
||||||
export const requireCreateStickerModal = extractAndLoadChunksLazy(["stickerInspected]:"]);
|
export const requireCreateStickerModal = extractAndLoadChunksLazy(["stickerInspected]:"]);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "#{intl::UNIGNORE_TO_JUMP_BODY}",
|
find: "#{intl::UNIGNORE_TO_JUMP_BODY}",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /return \i\.\i\.isBlockedForMessage\(/,
|
match: /if\(\i\.\i\.isBlockedForMessage\(/,
|
||||||
replace: "return true;$&"
|
replace: "return true;$&"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,6 @@
|
||||||
|
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
import { addMemberListDecorator, removeMemberListDecorator } from "@api/MemberListDecorators";
|
|
||||||
import { addMessageDecoration, removeMessageDecoration } from "@api/MessageDecorations";
|
|
||||||
import { addNicknameIcon, removeNicknameIcon } from "@api/NicknameIcons";
|
|
||||||
import { definePluginSettings, migratePluginSetting, Settings } from "@api/Settings";
|
import { definePluginSettings, migratePluginSetting, Settings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
|
|
@ -192,49 +189,22 @@ const PlatformIndicator = ({ user, isProfile, isMessage, isMemberList }: Platfor
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function toggleMemberListDecorators(enabled: boolean) {
|
|
||||||
if (enabled) {
|
|
||||||
addMemberListDecorator("PlatformIndicators", props => <PlatformIndicator user={props.user} isMemberList />);
|
|
||||||
} else {
|
|
||||||
removeMemberListDecorator("PlatformIndicators");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleNicknameIcons(enabled: boolean) {
|
|
||||||
if (enabled) {
|
|
||||||
addNicknameIcon("PlatformIndicators", props => <PlatformIndicator user={UserStore.getUser(props.userId)} isProfile />, 1);
|
|
||||||
} else {
|
|
||||||
removeNicknameIcon("PlatformIndicators");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleMessageDecorators(enabled: boolean) {
|
|
||||||
if (enabled) {
|
|
||||||
addMessageDecoration("PlatformIndicators", props => <PlatformIndicator user={props.message?.author} isMessage />);
|
|
||||||
} else {
|
|
||||||
removeMessageDecoration("PlatformIndicators");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
migratePluginSetting("PlatformIndicators", "profiles", "badges");
|
migratePluginSetting("PlatformIndicators", "profiles", "badges");
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
list: {
|
list: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
description: "Show indicators in the member list",
|
description: "Show indicators in the member list",
|
||||||
default: true,
|
default: true,
|
||||||
onChange: toggleMemberListDecorators
|
|
||||||
},
|
},
|
||||||
profiles: {
|
profiles: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
description: "Show indicators in user profiles",
|
description: "Show indicators in user profiles",
|
||||||
default: true,
|
default: true,
|
||||||
onChange: toggleNicknameIcons
|
|
||||||
},
|
},
|
||||||
messages: {
|
messages: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
description: "Show indicators inside messages",
|
description: "Show indicators inside messages",
|
||||||
default: true,
|
default: true,
|
||||||
onChange: toggleMessageDecorators
|
|
||||||
},
|
},
|
||||||
colorMobileIndicator: {
|
colorMobileIndicator: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
|
|
@ -278,19 +248,21 @@ export default definePlugin({
|
||||||
name: "PlatformIndicators",
|
name: "PlatformIndicators",
|
||||||
description: "Adds platform indicators (Desktop, Mobile, Web...) to users",
|
description: "Adds platform indicators (Desktop, Mobile, Web...) to users",
|
||||||
authors: [Devs.kemo, Devs.TheSun, Devs.Nuckyz, Devs.Ven],
|
authors: [Devs.kemo, Devs.TheSun, Devs.Nuckyz, Devs.Ven],
|
||||||
dependencies: ["MemberListDecoratorsAPI", "NicknameIconsAPI", "MessageDecorationsAPI"],
|
|
||||||
settings,
|
settings,
|
||||||
|
renderNicknameIcon(props) {
|
||||||
start() {
|
if (!settings.store.profiles) return null;
|
||||||
if (settings.store.list) toggleMemberListDecorators(true);
|
return (
|
||||||
if (settings.store.profiles) toggleNicknameIcons(true);
|
<PlatformIndicator user={UserStore.getUser(props.userId)} isProfile />
|
||||||
if (settings.store.messages) toggleMessageDecorators(true);
|
);
|
||||||
},
|
},
|
||||||
|
renderMemberListDecorator(props) {
|
||||||
|
if (!settings.store.list) return null;
|
||||||
|
return <PlatformIndicator user={props.user} isMemberList />;
|
||||||
|
|
||||||
stop() {
|
},
|
||||||
if (settings.store.list) toggleMemberListDecorators(false);
|
renderMessageDecoration(props) {
|
||||||
if (settings.store.profiles) toggleNicknameIcons;
|
if (!settings.store.messages) return null;
|
||||||
if (settings.store.messages) toggleMessageDecorators(false);
|
return <PlatformIndicator user={props.message?.author} isMessage />;
|
||||||
},
|
},
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { DataStore } from "@api/index";
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
import { definePluginSettings, Settings } from "@api/Settings";
|
import { definePluginSettings, Settings } from "@api/Settings";
|
||||||
|
|
@ -11,15 +12,21 @@ import { Devs, EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { GuildMember, Message, User } from "@vencord/discord-types";
|
import { GuildMember, Message, User } from "@vencord/discord-types";
|
||||||
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
||||||
import { ChannelStore, GuildMemberStore, GuildStore, MessageStore, RelationshipStore, StreamerModeStore, useEffect, UserStore } from "@webpack/common";
|
import { ChannelStore, GuildMemberStore, GuildStore, Menu, MessageStore, RelationshipStore, StreamerModeStore, TextInput, useEffect, UserStore, useState } from "@webpack/common";
|
||||||
import { JSX } from "react";
|
import { JSX } from "react";
|
||||||
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
|
import { Button, ErrorBoundary, Heading, TextButton } from "@components/index";
|
||||||
|
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/index";
|
||||||
|
|
||||||
const wrapEmojis = findByCodeLazy("lastIndex;return");
|
const wrapEmojis = findByCodeLazy("lastIndex;return");
|
||||||
const AccessibilityStore = findStoreLazy("AccessibilityStore");
|
const AccessibilityStore = findStoreLazy("AccessibilityStore");
|
||||||
const colorPattern = /^#(?:[\da-f]{3}){1,2}$|^#(?:[\da-f]{4}){1,2}$|(rgb|hsl)a?\((\s*-?\d+%?\s*,){2}(\s*-?\d+%?\s*)\)|(rgb|hsl)a?\((\s*-?\d+%?\s*,){3}\s*(0|(0?\.\d+)|1)\)$/iu;
|
const colorPattern = /^#(?:[\da-f]{3}){1,2}$|^#(?:[\da-f]{4}){1,2}$|(rgb|hsl)a?\((\s*-?\d+%?\s*,){2}(\s*-?\d+%?\s*)\)|(rgb|hsl)a?\((\s*-?\d+%?\s*,){3}\s*(0|(0?\.\d+)|1)\)$/iu;
|
||||||
const roleColorPattern = /^role((?:\+|-)\d{0,4})?$/iu;
|
const roleColorPattern = /^role((?:\+|-)\d{0,4})?$/iu;
|
||||||
const symbolPattern = /^[\p{S}\p{P}]{1,3}$/iu;
|
const symbolPattern = /^[\p{S}\p{P}]{1,3}$/iu;
|
||||||
const templatePattern = /(?:\{(?:friend|nick|display|user)(?:,\s*(?:friend|nick|display|user))*\})/iu;
|
const templatePattern = /(?:\{(?:custom|friend|nick|display|user)(?:,\s*(?:custom|friend|nick|display|user))*\})/iu;
|
||||||
|
|
||||||
|
type CustomNicknameData = Record<string, string>;
|
||||||
|
let customNicknames: CustomNicknameData = {};
|
||||||
|
|
||||||
function adjustHex(color: string, percent: number): string {
|
function adjustHex(color: string, percent: number): string {
|
||||||
let hex = color.replace("#", "");
|
let hex = color.replace("#", "");
|
||||||
|
|
@ -208,8 +215,8 @@ function validTemplate(value: string) {
|
||||||
suffix.length > 3 ||
|
suffix.length > 3 ||
|
||||||
(!!prefix && !symbolPattern.test(prefix)) ||
|
(!!prefix && !symbolPattern.test(prefix)) ||
|
||||||
(!!suffix && !symbolPattern.test(suffix)) ||
|
(!!suffix && !symbolPattern.test(suffix)) ||
|
||||||
targetProcessedNames.length > 4 ||
|
targetProcessedNames.length > 5 ||
|
||||||
targetProcessedNames.some(name => !["friend", "nick", "display", "user"].includes(name.trim()))
|
targetProcessedNames.some(name => !["custom", "friend", "nick", "display", "user"].includes(name.trim()))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -218,7 +225,13 @@ function validTemplate(value: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProcessedNames(author: any, truncateAllNamesWithStreamerMode: boolean, discriminators: boolean): [string | null, string | null, string | null, string | null] {
|
function getProcessedNames(author: any, truncateAllNamesWithStreamerMode: boolean, discriminators: boolean): {
|
||||||
|
username: string | null;
|
||||||
|
display: string | null;
|
||||||
|
nick: string | null;
|
||||||
|
friend: string | null;
|
||||||
|
custom: string | null;
|
||||||
|
} {
|
||||||
let discriminator: string | null = null;
|
let discriminator: string | null = null;
|
||||||
|
|
||||||
if (discriminators) {
|
if (discriminators) {
|
||||||
|
|
@ -254,7 +267,13 @@ function getProcessedNames(author: any, truncateAllNamesWithStreamerMode: boolea
|
||||||
? friendName[0] + "..."
|
? friendName[0] + "..."
|
||||||
: friendName as string;
|
: friendName as string;
|
||||||
|
|
||||||
return [username, display, nick, friend];
|
const customName: string | null = !author?.id ? null : customNicknames[author.id] || null;
|
||||||
|
const custom: string | null = !customName ? null
|
||||||
|
: StreamerModeStore.enabled && (truncateAllNamesWithStreamerMode || customName.toLowerCase() === author.username.toLowerCase())
|
||||||
|
? customName[0] + "..."
|
||||||
|
: customName;
|
||||||
|
|
||||||
|
return { username, display, nick, friend, custom };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface mentionProps {
|
interface mentionProps {
|
||||||
|
|
@ -351,8 +370,8 @@ function renderUsername(
|
||||||
const isReaction = isReactionsTooltip || isReactionsPopout;
|
const isReaction = isReactionsTooltip || isReactionsPopout;
|
||||||
const isVoice = type === "voiceChannel";
|
const isVoice = type === "voiceChannel";
|
||||||
|
|
||||||
const config = hookless ? settings.store : settings.use(["messages", "replies", "mentions", "memberList", "profilePopout", "reactions", "discriminators", "hideDefaultAtSign", "truncateAllNamesWithStreamerMode", "removeDuplicates", "ignoreGradients", "ignoreFonts", "animateGradients", "includedNames", "friendNameColor", "nicknameColor", "displayNameColor", "usernameColor", "nameSeparator", "triggerNameRerender"]);
|
const config = hookless ? settings.store : settings.use(["messages", "replies", "mentions", "memberList", "profilePopout", "reactions", "discriminators", "hideDefaultAtSign", "truncateAllNamesWithStreamerMode", "removeDuplicates", "ignoreGradients", "ignoreFonts", "animateGradients", "includedNames", "customNameColor", "friendNameColor", "nicknameColor", "displayNameColor", "usernameColor", "nameSeparator", "triggerNameRerender"]);
|
||||||
const { messages, replies, mentions, memberList, profilePopout, reactions, discriminators, hideDefaultAtSign, truncateAllNamesWithStreamerMode, removeDuplicates, ignoreGradients, ignoreFonts, animateGradients, includedNames, friendNameColor, nicknameColor, displayNameColor, usernameColor, nameSeparator, triggerNameRerender } = config;
|
const { messages, replies, mentions, memberList, profilePopout, reactions, discriminators, hideDefaultAtSign, truncateAllNamesWithStreamerMode, removeDuplicates, ignoreGradients, ignoreFonts, animateGradients, includedNames, customNameColor, friendNameColor, nicknameColor, displayNameColor, usernameColor, nameSeparator, triggerNameRerender } = config;
|
||||||
|
|
||||||
const canUseGradient = ((author as GuildMember)?.guildId ? (GuildStore.getGuild((author as GuildMember).guildId) ?? {}).premiumFeatures?.features.includes("ENHANCED_ROLE_COLORS") : false);
|
const canUseGradient = ((author as GuildMember)?.guildId ? (GuildStore.getGuild((author as GuildMember).guildId) ?? {}).premiumFeatures?.features.includes("ENHANCED_ROLE_COLORS") : false);
|
||||||
const textMutedValue = getComputedStyle(document.documentElement)?.getPropertyValue("--text-muted")?.trim() || "#72767d";
|
const textMutedValue = getComputedStyle(document.documentElement)?.getPropertyValue("--text-muted")?.trim() || "#72767d";
|
||||||
|
|
@ -361,14 +380,16 @@ function renderUsername(
|
||||||
const resolvedDisplayNameColor = author ? resolveColor(author, displayNameColor.trim(), "", canUseGradient) : null;
|
const resolvedDisplayNameColor = author ? resolveColor(author, displayNameColor.trim(), "", canUseGradient) : null;
|
||||||
const resolvedNicknameColor = author ? resolveColor(author, nicknameColor.trim(), "", canUseGradient) : null;
|
const resolvedNicknameColor = author ? resolveColor(author, nicknameColor.trim(), "", canUseGradient) : null;
|
||||||
const resolvedFriendNameColor = author ? resolveColor(author, friendNameColor.trim(), "", canUseGradient) : null;
|
const resolvedFriendNameColor = author ? resolveColor(author, friendNameColor.trim(), "", canUseGradient) : null;
|
||||||
|
const resolvedCustomNameColor = author ? resolveColor(author, customNameColor.trim(), "", canUseGradient) : null;
|
||||||
const affixColor = { color: textMutedValue, "-webkit-text-fill-color": textMutedValue, isolation: "isolate", "white-space": "pre", "font-family": "var(--font-primary)", "letter-spacing": "normal" };
|
const affixColor = { color: textMutedValue, "-webkit-text-fill-color": textMutedValue, isolation: "isolate", "white-space": "pre", "font-family": "var(--font-primary)", "letter-spacing": "normal" };
|
||||||
const [username, display, nick, friend] = getProcessedNames(author, truncateAllNamesWithStreamerMode, discriminators);
|
const { username, display, nick, friend, custom } = getProcessedNames(author, truncateAllNamesWithStreamerMode, discriminators);
|
||||||
|
|
||||||
const names: Record<string, [string | null, object | null]> = {
|
const names: Record<string, [string | null, object | null]> = {
|
||||||
user: [username, resolvedUsernameColor],
|
user: [username, resolvedUsernameColor],
|
||||||
display: [display, resolvedDisplayNameColor],
|
display: [display, resolvedDisplayNameColor],
|
||||||
nick: [nick, resolvedNicknameColor],
|
nick: [nick, resolvedNicknameColor],
|
||||||
friend: [friend, resolvedFriendNameColor],
|
friend: [friend, resolvedFriendNameColor],
|
||||||
|
custom: [custom, resolvedCustomNameColor]
|
||||||
};
|
};
|
||||||
|
|
||||||
const outputs: any[] = [];
|
const outputs: any[] = [];
|
||||||
|
|
@ -421,6 +442,7 @@ function renderUsername(
|
||||||
let second = outputs.shift();
|
let second = outputs.shift();
|
||||||
let third = outputs.shift();
|
let third = outputs.shift();
|
||||||
let fourth = outputs.shift();
|
let fourth = outputs.shift();
|
||||||
|
let fifth = outputs.shift();
|
||||||
|
|
||||||
const firstValueWrapped = hookless ?
|
const firstValueWrapped = hookless ?
|
||||||
(first.name || "")
|
(first.name || "")
|
||||||
|
|
@ -438,10 +460,15 @@ function renderUsername(
|
||||||
((fourth ?? {}).name || "")
|
((fourth ?? {}).name || "")
|
||||||
: wrapEmojis((fourth ?? {}).name || "");
|
: wrapEmojis((fourth ?? {}).name || "");
|
||||||
|
|
||||||
|
const fifthValueWrapped = hookless ?
|
||||||
|
((fifth ?? {}).name || "")
|
||||||
|
: wrapEmojis((fifth ?? {}).name || "");
|
||||||
|
|
||||||
first.wrapped = firstValueWrapped;
|
first.wrapped = firstValueWrapped;
|
||||||
second && (second.wrapped = secondValueWrapped);
|
second && (second.wrapped = secondValueWrapped);
|
||||||
third && (third.wrapped = thirdValueWrapped);
|
third && (third.wrapped = thirdValueWrapped);
|
||||||
fourth && (fourth.wrapped = fourthValueWrapped);
|
fourth && (fourth.wrapped = fourthValueWrapped);
|
||||||
|
fifth && (fifth.wrapped = fifthValueWrapped);
|
||||||
|
|
||||||
if (isMessage && !messages) {
|
if (isMessage && !messages) {
|
||||||
return [null, null, null];
|
return [null, null, null];
|
||||||
|
|
@ -462,10 +489,14 @@ function renderUsername(
|
||||||
return [fallbackText, <>{fallbackText}</>, fallbackText];
|
return [fallbackText, <>{fallbackText}</>, fallbackText];
|
||||||
}
|
}
|
||||||
|
|
||||||
const prioritizeUsername = (new Set([first, second, third, fourth].filter(Boolean).map(pos => pos.name.toLowerCase())).size > 1);
|
const prioritizeUsername = (new Set([first, second, third, fourth, fifth].filter(Boolean).map(pos => pos.name.toLowerCase())).size > 1);
|
||||||
|
|
||||||
if (removeDuplicates) {
|
if (removeDuplicates) {
|
||||||
// Remove duplicates from back to front. Prioritize the earlier name, unless it's the username and there's more than one unique option, then prioritize it.
|
// Remove duplicates from back to front. Prioritize the earlier name, unless it's the username and there's more than one unique option, then prioritize it.
|
||||||
|
fifth && fourth && fifth.name.toLowerCase() === fourth.name.toLowerCase() ? fifth.type === "user" && prioritizeUsername ? fourth = null : fifth = null : null;
|
||||||
|
fifth && third && fifth.name.toLowerCase() === third.name.toLowerCase() ? fifth.type === "user" && prioritizeUsername ? third = null : fifth = null : null;
|
||||||
|
fifth && second && fifth.name.toLowerCase() === second.name.toLowerCase() ? fifth.type === "user" && prioritizeUsername ? second = null : fifth = null : null;
|
||||||
|
fifth && first && fifth.name.toLowerCase() === first.name.toLowerCase() ? fifth.type === "user" && prioritizeUsername ? first = null : fifth = null : null;
|
||||||
fourth && third && fourth.name.toLowerCase() === third.name.toLowerCase() ? fourth.type === "user" && prioritizeUsername ? third = null : fourth = null : null;
|
fourth && third && fourth.name.toLowerCase() === third.name.toLowerCase() ? fourth.type === "user" && prioritizeUsername ? third = null : fourth = null : null;
|
||||||
fourth && second && fourth.name.toLowerCase() === second.name.toLowerCase() ? fourth.type === "user" && prioritizeUsername ? second = null : fourth = null : null;
|
fourth && second && fourth.name.toLowerCase() === second.name.toLowerCase() ? fourth.type === "user" && prioritizeUsername ? second = null : fourth = null : null;
|
||||||
fourth && first && fourth.name.toLowerCase() === first.name.toLowerCase() ? fourth.type === "user" && prioritizeUsername ? first = null : fourth = null : null;
|
fourth && first && fourth.name.toLowerCase() === first.name.toLowerCase() ? fourth.type === "user" && prioritizeUsername ? first = null : fourth = null : null;
|
||||||
|
|
@ -474,11 +505,12 @@ function renderUsername(
|
||||||
second && first && second.name.toLowerCase() === first.name.toLowerCase() ? second.type === "user" && prioritizeUsername ? first = null : second = null : null;
|
second && first && second.name.toLowerCase() === first.name.toLowerCase() ? second.type === "user" && prioritizeUsername ? first = null : second = null : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const remainingNames = [first, second, third, fourth].filter(Boolean);
|
const remainingNames = [first, second, third, fourth, fifth].filter(Boolean);
|
||||||
first = remainingNames.shift();
|
first = remainingNames.shift();
|
||||||
second = remainingNames.shift();
|
second = remainingNames.shift();
|
||||||
third = remainingNames.shift();
|
third = remainingNames.shift();
|
||||||
fourth = remainingNames.shift();
|
fourth = remainingNames.shift();
|
||||||
|
fifth = remainingNames.shift();
|
||||||
|
|
||||||
const useTopRoleStyle = isMention || isReactionsPopout;
|
const useTopRoleStyle = isMention || isReactionsPopout;
|
||||||
const topRoleStyle = resolveColor(author, "Role", "", canUseGradient);
|
const topRoleStyle = resolveColor(author, "Role", "", canUseGradient);
|
||||||
|
|
@ -500,7 +532,8 @@ function renderUsername(
|
||||||
const secondDataText = second && shouldAnimateSecondaryNames ? (second.prefix + second.name + second.suffix) : "";
|
const secondDataText = second && shouldAnimateSecondaryNames ? (second.prefix + second.name + second.suffix) : "";
|
||||||
const thirdDataText = third && shouldAnimateSecondaryNames ? (third.prefix + third.name + third.suffix) : "";
|
const thirdDataText = third && shouldAnimateSecondaryNames ? (third.prefix + third.name + third.suffix) : "";
|
||||||
const fourthDataText = fourth && shouldAnimateSecondaryNames ? (fourth.prefix + fourth.name + fourth.suffix) : "";
|
const fourthDataText = fourth && shouldAnimateSecondaryNames ? (fourth.prefix + fourth.name + fourth.suffix) : "";
|
||||||
const allDataText = [firstDataText, secondDataText, thirdDataText, fourthDataText].filter(Boolean).join(nameSeparator).trim();
|
const fifthDataText = fifth && shouldAnimateSecondaryNames ? (fifth.prefix + fifth.name + fifth.suffix) : "";
|
||||||
|
const allDataText = [firstDataText, secondDataText, thirdDataText, fourthDataText, fifthDataText].filter(Boolean).join(nameSeparator).trim();
|
||||||
|
|
||||||
// Only mentions and reactions popouts should patch in the gradient glow or else a double glow will appear on messages.
|
// Only mentions and reactions popouts should patch in the gradient glow or else a double glow will appear on messages.
|
||||||
const hoveringClass = (isHovering ? " show-me-your-name-gradient-hovered" : "");
|
const hoveringClass = (isHovering ? " show-me-your-name-gradient-hovered" : "");
|
||||||
|
|
@ -512,10 +545,12 @@ function renderUsername(
|
||||||
const secondGroupClasses = "show-me-your-name-name-group show-me-your-name-second-name-group";
|
const secondGroupClasses = "show-me-your-name-name-group show-me-your-name-second-name-group";
|
||||||
const thirdGroupClasses = "show-me-your-name-name-group show-me-your-name-third-name-group";
|
const thirdGroupClasses = "show-me-your-name-name-group show-me-your-name-third-name-group";
|
||||||
const fourthGroupClasses = "show-me-your-name-name-group show-me-your-name-fourth-name-group";
|
const fourthGroupClasses = "show-me-your-name-name-group show-me-your-name-fourth-name-group";
|
||||||
|
const fifthGroupClasses = "show-me-your-name-name-group show-me-your-name-fifth-name-group";
|
||||||
const firstNameClasses = "show-me-your-name-name show-me-your-name-first-name";
|
const firstNameClasses = "show-me-your-name-name show-me-your-name-first-name";
|
||||||
const secondNameClasses = "show-me-your-name-name show-me-your-name-second-name";
|
const secondNameClasses = "show-me-your-name-name show-me-your-name-second-name";
|
||||||
const thirdNameClasses = "show-me-your-name-name show-me-your-name-third-name";
|
const thirdNameClasses = "show-me-your-name-name show-me-your-name-third-name";
|
||||||
const fourthNameClasses = "show-me-your-name-name show-me-your-name-fourth-name";
|
const fourthNameClasses = "show-me-your-name-name show-me-your-name-fourth-name";
|
||||||
|
const fifthNameClasses = "show-me-your-name-name show-me-your-name-fifth-name";
|
||||||
const prefixClasses = "show-me-your-name-affix show-me-your-name-prefix";
|
const prefixClasses = "show-me-your-name-affix show-me-your-name-prefix";
|
||||||
const suffixClasses = "show-me-your-name-affix show-me-your-name-suffix";
|
const suffixClasses = "show-me-your-name-affix show-me-your-name-suffix";
|
||||||
|
|
||||||
|
|
@ -549,85 +584,39 @@ function renderUsername(
|
||||||
{first.wrapped}</span>
|
{first.wrapped}</span>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{second && (
|
{[
|
||||||
|
{ name: second, dataText: secondDataText, groupClass: secondGroupClasses, nameClass: secondNameClasses, position: "second" },
|
||||||
|
{ name: third, dataText: thirdDataText, groupClass: thirdGroupClasses, nameClass: thirdNameClasses, position: "third" },
|
||||||
|
{ name: fourth, dataText: fourthDataText, groupClass: fourthGroupClasses, nameClass: fourthNameClasses, position: "fourth" },
|
||||||
|
{ name: fifth, dataText: fifthDataText, groupClass: fifthGroupClasses, nameClass: fifthNameClasses, position: "fifth" }
|
||||||
|
].map(({ name, dataText, groupClass, nameClass, position }) => name && (
|
||||||
<span
|
<span
|
||||||
className={(shouldGradientGlow && shouldAnimateSecondaryNames ? (gradientClasses + " " + secondGroupClasses) : secondGroupClasses)}
|
key={position}
|
||||||
data-text={shouldGradientGlow && secondDataText ? secondDataText : undefined}
|
className={(shouldGradientGlow && shouldAnimateSecondaryNames ? (gradientClasses + " " + groupClass) : groupClass)}
|
||||||
style={(shouldGradientGlow && shouldAnimateSecondaryNames ? second.style.gradient.animated : undefined) as React.CSSProperties}
|
data-text={shouldGradientGlow && dataText ? dataText : undefined}
|
||||||
|
style={(shouldGradientGlow && shouldAnimateSecondaryNames ? name.style.gradient.animated : undefined) as React.CSSProperties}
|
||||||
>
|
>
|
||||||
<span style={affixColor as React.CSSProperties} className={prefixClasses}>
|
<span style={affixColor as React.CSSProperties} className={prefixClasses}>
|
||||||
<span>{nameSeparator}</span>
|
<span>{nameSeparator}</span>
|
||||||
{second.prefix}</span>
|
{name.prefix}</span>
|
||||||
<span
|
<span
|
||||||
// On non-primary names, allow disabling the gradients completely, or just their animation & glow.
|
// On non-primary names, allow disabling the gradients completely, or just their animation & glow.
|
||||||
className={secondNameClasses}
|
className={nameClass}
|
||||||
style={{
|
style={{
|
||||||
...(ignoreFonts ? { "font-family": "var(--font-primary)", "letter-spacing": "normal" } : {}),
|
...(ignoreFonts ? { "font-family": "var(--font-primary)", "letter-spacing": "normal" } : {}),
|
||||||
...(ignoreGradients
|
...(ignoreGradients
|
||||||
? second.style.normal.adjusted
|
? name.style.normal.adjusted
|
||||||
: shouldAnimateGradients && shouldAnimateSecondaryNames && second.style.gradient
|
: shouldAnimateGradients && shouldAnimateSecondaryNames && name.style.gradient
|
||||||
? second.style.gradient.animated
|
? name.style.gradient.animated
|
||||||
: second.style.gradient
|
: name.style.gradient
|
||||||
? second.style.gradient.static.original
|
? name.style.gradient.static.original
|
||||||
: second.style.normal.adjusted)
|
: name.style.normal.adjusted)
|
||||||
}}>
|
}}>
|
||||||
{second.wrapped}</span>
|
{name.wrapped}</span>
|
||||||
<span style={affixColor as React.CSSProperties} className={suffixClasses}>
|
<span style={affixColor as React.CSSProperties} className={suffixClasses}>
|
||||||
{second.suffix}</span>
|
{name.suffix}</span>
|
||||||
</span>
|
</span>
|
||||||
)}
|
))}
|
||||||
{third && (
|
|
||||||
<span
|
|
||||||
className={(shouldGradientGlow && shouldAnimateSecondaryNames ? (gradientClasses + " " + thirdGroupClasses) : thirdGroupClasses)}
|
|
||||||
data-text={shouldGradientGlow && thirdDataText ? thirdDataText : undefined}
|
|
||||||
style={(shouldGradientGlow && shouldAnimateSecondaryNames ? third.style.gradient.animated : undefined) as React.CSSProperties}
|
|
||||||
>
|
|
||||||
<span style={affixColor as React.CSSProperties} className={prefixClasses}>
|
|
||||||
<span>{nameSeparator}</span>
|
|
||||||
{third.prefix}</span>
|
|
||||||
<span
|
|
||||||
className={thirdNameClasses}
|
|
||||||
style={{
|
|
||||||
...(ignoreFonts ? { "font-family": "var(--font-primary)", "letter-spacing": "normal" } : {}),
|
|
||||||
...(ignoreGradients
|
|
||||||
? third.style.normal.adjusted
|
|
||||||
: shouldAnimateGradients && shouldAnimateSecondaryNames && third.style.gradient
|
|
||||||
? third.style.gradient.animated
|
|
||||||
: third.style.gradient
|
|
||||||
? third.style.gradient.static.original
|
|
||||||
: third.style.normal.adjusted)
|
|
||||||
}}>
|
|
||||||
{third.wrapped}</span>
|
|
||||||
<span style={affixColor as React.CSSProperties} className={suffixClasses}>
|
|
||||||
{third.suffix}</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{fourth && (
|
|
||||||
<span
|
|
||||||
className={(shouldGradientGlow && shouldAnimateSecondaryNames ? (gradientClasses + " " + fourthGroupClasses) : fourthGroupClasses)}
|
|
||||||
data-text={shouldGradientGlow && fourthDataText ? fourthDataText : undefined}
|
|
||||||
style={(shouldGradientGlow && shouldAnimateSecondaryNames ? fourth.style.gradient.animated : undefined) as React.CSSProperties}
|
|
||||||
>
|
|
||||||
<span style={affixColor as React.CSSProperties} className={prefixClasses}>
|
|
||||||
<span>{nameSeparator}</span>
|
|
||||||
{fourth.prefix}</span>
|
|
||||||
<span
|
|
||||||
className={fourthNameClasses}
|
|
||||||
style={{
|
|
||||||
...(ignoreFonts ? { "font-family": "var(--font-primary)", "letter-spacing": "normal" } : {}),
|
|
||||||
...(ignoreGradients
|
|
||||||
? fourth.style.normal.adjusted
|
|
||||||
: shouldAnimateGradients && shouldAnimateSecondaryNames && fourth.style.gradient
|
|
||||||
? fourth.style.gradient.animated
|
|
||||||
: fourth.style.gradient
|
|
||||||
? fourth.style.gradient.static.original
|
|
||||||
: fourth.style.normal.adjusted)
|
|
||||||
}}>
|
|
||||||
{fourth.wrapped}</span>
|
|
||||||
<span style={affixColor as React.CSSProperties} className={suffixClasses}>
|
|
||||||
{fourth.suffix}</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -688,6 +677,98 @@ function removeHoveringReactionPopout(id: string) {
|
||||||
settings.store.triggerNameRerender = !settings.store.triggerNameRerender;
|
settings.store.triggerNameRerender = !settings.store.triggerNameRerender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CustomNicknameModal({ modalProps, user }: { modalProps: ModalProps; user: User; }) {
|
||||||
|
const [value, setValue] = useState(customNicknames[user.id] ?? "");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalRoot {...modalProps}>
|
||||||
|
<ModalHeader>
|
||||||
|
<Heading tag="h1" style={{ flexGrow: 1, margin: 0 }}>
|
||||||
|
{customNicknames[user.id] ? "Change SMYN Nickname" : "Add SMYN Nickname"}
|
||||||
|
</Heading>
|
||||||
|
<ModalCloseButton onClick={modalProps.onClose} />
|
||||||
|
</ModalHeader>
|
||||||
|
<ModalContent>
|
||||||
|
<Heading tag="h3" style={{ marginBottom: 8, fontSize: "16px", fontWeight: "400", lineHeight: "1.25", color: "var(--text-secondary)" }}>
|
||||||
|
{"Set a custom SMYN nickname for this user. Make use of it by specifying {custom} in the SMYN template settings."}
|
||||||
|
</Heading>
|
||||||
|
<div style={{ paddingTop: "10px", flexGrow: 0 }}></div>
|
||||||
|
<Heading tag="h3" style={{ marginBottom: 8, fontSize: "14px", fontWeight: 600 }}>
|
||||||
|
SMYN Nickname
|
||||||
|
</Heading>
|
||||||
|
<TextInput
|
||||||
|
value={value}
|
||||||
|
maxLength={32}
|
||||||
|
onChange={setValue}
|
||||||
|
placeholder={user.globalName ?? user.username}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
/>
|
||||||
|
<TextButton
|
||||||
|
className="show-me-your-name-reset-button"
|
||||||
|
onClick={async () => {
|
||||||
|
setValue("");
|
||||||
|
delete customNicknames[user.id];
|
||||||
|
await DataStore.set("SMYNCustomNicknames", customNicknames);
|
||||||
|
settings.store.triggerNameRerender = !settings.store.triggerNameRerender;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Reset SMYN Nickname
|
||||||
|
</TextButton>
|
||||||
|
<div style={{ paddingTop: "10px", flexGrow: 0 }}></div>
|
||||||
|
</ModalContent>
|
||||||
|
<ModalFooter className="show-me-your-name-modal-footer-container">
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
onClick={async () => {
|
||||||
|
const trimmed = value.trim().slice(0, 32).trim();
|
||||||
|
|
||||||
|
if (trimmed) {
|
||||||
|
customNicknames[user.id] = trimmed;
|
||||||
|
} else {
|
||||||
|
delete customNicknames[user.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
await DataStore.set("SMYNCustomNicknames", customNicknames);
|
||||||
|
settings.store.triggerNameRerender = !settings.store.triggerNameRerender;
|
||||||
|
modalProps.onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
style={{ marginRight: "8px" }}
|
||||||
|
onClick={modalProps.onClose}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalRoot>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userContextPatch: NavContextMenuPatchCallback = (children, { user }) => {
|
||||||
|
if (!user) return;
|
||||||
|
|
||||||
|
const currentUser = UserStore.getCurrentUser();
|
||||||
|
if (!currentUser || user.id === currentUser.id) return;
|
||||||
|
|
||||||
|
const group = findGroupChildrenByChildId("user-profile", children);
|
||||||
|
|
||||||
|
!group && children.push(<Menu.MenuSeparator />);
|
||||||
|
(group || children).push(
|
||||||
|
<Menu.MenuItem
|
||||||
|
id="smyn-custom-nickname"
|
||||||
|
label={customNicknames[user.id] ? "Change SMYN Nickname" : "Add SMYN Nickname"}
|
||||||
|
action={() => openModal(props => (
|
||||||
|
<ErrorBoundary>
|
||||||
|
<CustomNicknameModal modalProps={props} user={user} />
|
||||||
|
</ErrorBoundary>
|
||||||
|
))}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
messages: {
|
messages: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
|
|
@ -747,17 +828,17 @@ const settings = definePluginSettings({
|
||||||
ignoreFonts: {
|
ignoreFonts: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
default: false,
|
default: false,
|
||||||
description: "For the second, third, and fourth names, use GG SANS regardless of the user's custom font.",
|
description: "For the non-primary names, use Discord's default fonts regardless of the user's custom nitro font.",
|
||||||
},
|
},
|
||||||
ignoreGradients: {
|
ignoreGradients: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
default: true,
|
default: true,
|
||||||
description: "For the second, third, and fourth names, if the role has a gradient, ignore it in favor of the value below.",
|
description: "For the non-primary names, if the role has a gradient, ignore it in favor of the color set below.",
|
||||||
},
|
},
|
||||||
animateGradients: {
|
animateGradients: {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
default: false,
|
default: false,
|
||||||
description: "For the second, third, and fourth names, if the role has a gradient, animate it. This is disabled by \"Ignore Gradients\" and reduced motion.",
|
description: "For the non-primary names, if the role has a gradient, animate it. This is disabled by \"Ignore Gradients\" and reduced motion.",
|
||||||
},
|
},
|
||||||
nameSeparator: {
|
nameSeparator: {
|
||||||
type: OptionType.STRING,
|
type: OptionType.STRING,
|
||||||
|
|
@ -766,10 +847,16 @@ const settings = definePluginSettings({
|
||||||
},
|
},
|
||||||
includedNames: {
|
includedNames: {
|
||||||
type: OptionType.STRING,
|
type: OptionType.STRING,
|
||||||
description: "The order to display usernames, display names, nicknames, and friend names. Use the following placeholders: {user}, {display}, {nick}, {friend}. You can provide multiple name options to use as fallbacks if one is unavailable by separating them with commas as such: {friend, nick, display}. You can have up to three prefixes and three suffixes per name.",
|
description: "The order to display usernames, display names, nicknames, friend names, and custom names. Use the following placeholders: {user}, {display}, {nick}, {friend}, {custom}. You can provide multiple name options to use as fallbacks if one is unavailable by separating them with commas as such: {custom, friend, nick}. You can have up to three prefixes and three suffixes per name.",
|
||||||
default: "{friend, nick} [{display}] (@{user})",
|
default: "{custom, friend, nick} [{display}] (@{user})",
|
||||||
isValid: validTemplate,
|
isValid: validTemplate,
|
||||||
},
|
},
|
||||||
|
customNameColor: {
|
||||||
|
type: OptionType.STRING,
|
||||||
|
description: "The color to use for the custom name you assigned a user if it's not the first displayed. Leave blank for default. Accepts hex(a), rgb(a), or hsl(a) input. Use \"Role\" to follow the user's top role color. Use \"Role+-#\" to adjust the brightness by that percentage (ex: \"Role+15\")",
|
||||||
|
default: "Role-25",
|
||||||
|
isValid: validColor,
|
||||||
|
},
|
||||||
friendNameColor: {
|
friendNameColor: {
|
||||||
type: OptionType.STRING,
|
type: OptionType.STRING,
|
||||||
description: "The color to use for a friend's nickname if it's not the first displayed. Leave blank for default. Accepts hex(a), rgb(a), or hsl(a) input. Use \"Role\" to follow the user's top role color. Use \"Role+-#\" to adjust the brightness by that percentage (ex: \"Role+15\")",
|
description: "The color to use for a friend's nickname if it's not the first displayed. Leave blank for default. Accepts hex(a), rgb(a), or hsl(a) input. Use \"Role\" to follow the user's top role color. Use \"Role+-#\" to adjust the brightness by that percentage (ex: \"Role+15\")",
|
||||||
|
|
@ -804,8 +891,9 @@ const settings = definePluginSettings({
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ShowMeYourName",
|
name: "ShowMeYourName",
|
||||||
description: "Display any permutation of nicknames, display names, and usernames in chat.",
|
description: "Display any permutation of custom nicknames, friend nicknames, server nicknames, display names, and usernames in chat.",
|
||||||
authors: [Devs.Rini, Devs.TheKodeToad, EquicordDevs.Etorix, Devs.sadan],
|
authors: [Devs.Rini, Devs.TheKodeToad, EquicordDevs.Etorix, Devs.sadan, EquicordDevs.Prism],
|
||||||
|
tags: ["SMYN", "Nicknames", "Custom Nicknames",],
|
||||||
isModified: true,
|
isModified: true,
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
|
|
@ -943,6 +1031,15 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
const data = await DataStore.get<CustomNicknameData>("SMYNCustomNicknames");
|
||||||
|
customNicknames = data ?? {};
|
||||||
|
},
|
||||||
|
|
||||||
|
contextMenus: {
|
||||||
|
"user-context": userContextPatch
|
||||||
|
},
|
||||||
|
|
||||||
flux: {
|
flux: {
|
||||||
RELATIONSHIP_UPDATE(data) {
|
RELATIONSHIP_UPDATE(data) {
|
||||||
// Allows rerendering when changing friend names.
|
// Allows rerendering when changing friend names.
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,13 @@
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
transition: opacity .1s ease-in-out
|
transition: opacity .1s ease-in-out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.show-me-your-name-modal-footer-container button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-me-your-name-reset-button {
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
@ -201,6 +201,14 @@ const SilentTypingChatToggle: ChatBarButtonFactory = ({ channel, type }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function SilentTypingChatIcon() {
|
||||||
|
return (
|
||||||
|
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style={{ scale: "1.2" }}>
|
||||||
|
<path fill="currentColor" d="M18.333 15.556H1.667a1.667 1.667 0 0 1 -1.667 -1.667v-10a1.667 1.667 0 0 1 1.667 -1.667h16.667a1.667 1.667 0 0 1 1.667 1.667v10a1.667 1.667 0 0 1 -1.667 1.667M4.444 6.25V4.861a0.417 0.417 0 0 0 -0.417 -0.417H2.639a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V4.861a0.417 0.417 0 0 0 -0.417 -0.417H5.973a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V4.861a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V4.861a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V4.861a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m-11.667 3.333V8.194a0.417 0.417 0 0 0 -0.417 -0.417H4.306a0.417 0.417 0 0 0 -0.417 0.417V9.583a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V8.194a0.417 0.417 0 0 0 -0.417 -0.417H7.639a0.417 0.417 0 0 0 -0.417 0.417V9.583a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V8.194a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V9.583a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V8.194a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V9.583a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m-11.667 3.333v-1.389a0.417 0.417 0 0 0 -0.417 -0.417H2.639a0.417 0.417 0 0 0 -0.417 0.417V12.917a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m10 0v-1.389a0.417 0.417 0 0 0 -0.417 -0.417H5.973a0.417 0.417 0 0 0 -0.417 0.417V12.917a0.417 0.417 0 0 0 0.417 0.417h8.056a0.417 0.417 0 0 0 0.417 -0.417m3.333 0v-1.389a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V12.917a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417" transform="translate(2, 3)" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function getEffectiveList(): string[] {
|
function getEffectiveList(): string[] {
|
||||||
if (settings.store.defaultHidden) {
|
if (settings.store.defaultHidden) {
|
||||||
if (!settings.store.disabledLocations) {
|
if (!settings.store.disabledLocations) {
|
||||||
|
|
@ -288,7 +296,6 @@ export default definePlugin({
|
||||||
name: "SilentTyping",
|
name: "SilentTyping",
|
||||||
authors: [Devs.Ven, Devs.Rini, Devs.ImBanana, EquicordDevs.Etorix],
|
authors: [Devs.Ven, Devs.Rini, Devs.ImBanana, EquicordDevs.Etorix],
|
||||||
description: "Hide your typing indicator from chat.",
|
description: "Hide your typing indicator from chat.",
|
||||||
dependencies: ["ChatInputButtonAPI"],
|
|
||||||
isModified: true,
|
isModified: true,
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
|
|
@ -298,6 +305,10 @@ export default definePlugin({
|
||||||
contextMenus: {
|
contextMenus: {
|
||||||
"textarea-context": ChatBarContextCheckbox
|
"textarea-context": ChatBarContextCheckbox
|
||||||
},
|
},
|
||||||
|
chatBarButton: {
|
||||||
|
icon: SilentTypingChatIcon,
|
||||||
|
render: SilentTypingChatToggle
|
||||||
|
},
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
|
|
@ -425,6 +436,4 @@ export default definePlugin({
|
||||||
if (checkEnabled(channelId)) return;
|
if (checkEnabled(channelId)) return;
|
||||||
FluxDispatcher.dispatch({ type: "TYPING_START_LOCAL", channelId });
|
FluxDispatcher.dispatch({ type: "TYPING_START_LOCAL", channelId });
|
||||||
},
|
},
|
||||||
|
|
||||||
renderChatBarButton: SilentTypingChatToggle,
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,6 @@
|
||||||
|
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
import { addMemberListDecorator, removeMemberListDecorator } from "@api/MemberListDecorators";
|
|
||||||
import { addMessageDecoration, removeMessageDecoration } from "@api/MessageDecorations";
|
|
||||||
import { addNicknameIcon, removeNicknameIcon } from "@api/NicknameIcons";
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs, EquicordDevs } from "@utils/constants";
|
import { Devs, EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
|
@ -52,9 +49,22 @@ export default definePlugin({
|
||||||
name: "UserVoiceShow",
|
name: "UserVoiceShow",
|
||||||
description: "Shows an indicator when a user is in a Voice Channel",
|
description: "Shows an indicator when a user is in a Voice Channel",
|
||||||
authors: [Devs.Nuckyz, Devs.LordElias, EquicordDevs.omaw],
|
authors: [Devs.Nuckyz, Devs.LordElias, EquicordDevs.omaw],
|
||||||
dependencies: ["NicknameIconsAPI", "MemberListDecoratorsAPI", "MessageDecorationsAPI"],
|
|
||||||
settings,
|
settings,
|
||||||
|
renderNicknameIcon({ userId }) {
|
||||||
|
if (!settings.store.showInUserProfileModal) return null;
|
||||||
|
return (
|
||||||
|
<VoiceChannelIndicator userId={userId} isProfile />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
renderMemberListDecorator({ user }) {
|
||||||
|
if (!settings.store.showInMemberList) return null;
|
||||||
|
return user == null ? null : <VoiceChannelIndicator userId={user.id} />;
|
||||||
|
|
||||||
|
},
|
||||||
|
renderMessageDecoration({ message }) {
|
||||||
|
if (!settings.store.showInMessages) return null;
|
||||||
|
return message?.author == null ? null : <VoiceChannelIndicator userId={message.author.id} isMessageIndicator />;
|
||||||
|
},
|
||||||
patches: [
|
patches: [
|
||||||
// Friends List
|
// Friends List
|
||||||
{
|
{
|
||||||
|
|
@ -67,23 +77,5 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
start() {
|
|
||||||
if (settings.store.showInUserProfileModal) {
|
|
||||||
addNicknameIcon("UserVoiceShow", ({ userId }) => <VoiceChannelIndicator userId={userId} isProfile />);
|
|
||||||
}
|
|
||||||
if (settings.store.showInMemberList) {
|
|
||||||
addMemberListDecorator("UserVoiceShow", ({ user }) => user == null ? null : <VoiceChannelIndicator userId={user.id} />);
|
|
||||||
}
|
|
||||||
if (settings.store.showInMessages) {
|
|
||||||
addMessageDecoration("UserVoiceShow", ({ message }) => message?.author == null ? null : <VoiceChannelIndicator userId={message.author.id} isMessageIndicator />);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeNicknameIcon("UserVoiceShow");
|
|
||||||
removeMemberListDecorator("UserVoiceShow");
|
|
||||||
removeMessageDecoration("UserVoiceShow");
|
|
||||||
},
|
|
||||||
|
|
||||||
VoiceChannelIndicator
|
VoiceChannelIndicator
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -632,7 +632,7 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
||||||
alfred: {
|
alfred: {
|
||||||
name: "alfred",
|
name: "alfred",
|
||||||
id: 1038466644353232967n
|
id: 1038466644353232967n
|
||||||
}
|
},
|
||||||
} satisfies Record<string, Dev>);
|
} satisfies Record<string, Dev>);
|
||||||
|
|
||||||
export const EquicordDevs = Object.freeze({
|
export const EquicordDevs = Object.freeze({
|
||||||
|
|
@ -1205,7 +1205,7 @@ export const EquicordDevs = Object.freeze({
|
||||||
name: "neoarz",
|
name: "neoarz",
|
||||||
id: 1015372540937502851n
|
id: 1015372540937502851n
|
||||||
},
|
},
|
||||||
KamiRu:{
|
KamiRu: {
|
||||||
name: "KamiRu",
|
name: "KamiRu",
|
||||||
id: 819191621676695563n
|
id: 819191621676695563n
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,11 @@ import { Patch, PatchReplacement, ReplaceFn } from "./types";
|
||||||
// @ts-expect-error "RegExp.escape" is very new and not yet in DOM types
|
// @ts-expect-error "RegExp.escape" is very new and not yet in DOM types
|
||||||
const escapeRegex = RegExp.escape || ((s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
const escapeRegex = RegExp.escape || ((s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
||||||
|
|
||||||
export function getReplacement(isString: boolean, hashed: string) {
|
export function getReplacement(isString: boolean, hashed: string, hash: boolean = false) {
|
||||||
const hasSpecialChars = !Number.isNaN(Number(hashed[0])) || hashed.includes("+") || hashed.includes("/");
|
const hasSpecialChars = !Number.isNaN(Number(hashed[0])) || hashed.includes("+") || hashed.includes("/");
|
||||||
|
|
||||||
|
if (hash) return hashed;
|
||||||
|
|
||||||
if (hasSpecialChars) {
|
if (hasSpecialChars) {
|
||||||
return isString
|
return isString
|
||||||
? `["${hashed}"]`
|
? `["${hashed}"]`
|
||||||
|
|
@ -48,7 +50,7 @@ function canonicalizeMatchCompatString(str: string) {
|
||||||
const re = /#{intl::([\w$+/]*)(?:::(\w+))?}/g;
|
const re = /#{intl::([\w$+/]*)(?:::(\w+))?}/g;
|
||||||
for (const match of str.matchAll(re)) {
|
for (const match of str.matchAll(re)) {
|
||||||
result += escapeRegex(str.slice(lastIndex, match.index));
|
result += escapeRegex(str.slice(lastIndex, match.index));
|
||||||
result += getCompatReplacement(match[1]);
|
result += match[2] === "raw" ? getReplacement(false, match[1]) : match[2] === "hash" ? getReplacement(false, runtimeHashMessageKey(match[1]), true) : getCompatReplacement(match[1]);
|
||||||
lastIndex = (match.index ?? 0) + match[0].length;
|
lastIndex = (match.index ?? 0) + match[0].length;
|
||||||
}
|
}
|
||||||
result += escapeRegex(str.slice(lastIndex));
|
result += escapeRegex(str.slice(lastIndex));
|
||||||
|
|
@ -63,6 +65,7 @@ export function canonicalizeMatch<T extends RegExp | string>(match: T): T extend
|
||||||
let partialCanon = typeof match === "string" ? match : match.source;
|
let partialCanon = typeof match === "string" ? match : match.source;
|
||||||
partialCanon = partialCanon.replaceAll(/#{intl::([\w$+/]*)(?:::(\w+))?}/g, (_, key, modifier) => {
|
partialCanon = partialCanon.replaceAll(/#{intl::([\w$+/]*)(?:::(\w+))?}/g, (_, key, modifier) => {
|
||||||
if (modifier === "raw") return getReplacement(false, key);
|
if (modifier === "raw") return getReplacement(false, key);
|
||||||
|
if (modifier === "hash") return getReplacement(false, runtimeHashMessageKey(key), true);
|
||||||
return getCompatReplacement(key);
|
return getCompatReplacement(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,11 @@
|
||||||
* 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 { AudioProcessor } from "@api/AudioPlayer";
|
||||||
import type { ProfileBadge } from "@api/Badges";
|
import type { ProfileBadge } from "@api/Badges";
|
||||||
import type { ChatBarButtonData, ChatBarButtonFactory } from "@api/ChatButtons";
|
import type { ChatBarButtonData, ChatBarButtonFactory } from "@api/ChatButtons";
|
||||||
import type { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
import type { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
|
import { HeaderBarButtonFactory } from "@api/HeaderBar";
|
||||||
import type { MemberListDecoratorFactory } from "@api/MemberListDecorators";
|
import type { MemberListDecoratorFactory } from "@api/MemberListDecorators";
|
||||||
import type { MessageAccessoryFactory } from "@api/MessageAccessories";
|
import type { MessageAccessoryFactory } from "@api/MessageAccessories";
|
||||||
import type { MessageDecorationFactory } from "@api/MessageDecorations";
|
import type { MessageDecorationFactory } from "@api/MessageDecorations";
|
||||||
|
|
@ -195,7 +197,11 @@ export interface PluginDef {
|
||||||
renderMessageDecoration?: MessageDecorationFactory;
|
renderMessageDecoration?: MessageDecorationFactory;
|
||||||
|
|
||||||
renderMemberListDecorator?: MemberListDecoratorFactory;
|
renderMemberListDecorator?: MemberListDecoratorFactory;
|
||||||
|
|
||||||
|
// Custom
|
||||||
renderNicknameIcon?: NicknameIconFactory;
|
renderNicknameIcon?: NicknameIconFactory;
|
||||||
|
renderHeaderBarButton?: HeaderBarButtonFactory;
|
||||||
|
audioProcessor?: AudioProcessor;
|
||||||
|
|
||||||
// TODO: Remove eventually
|
// TODO: Remove eventually
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
import type * as t from "@vencord/discord-types";
|
import type * as t from "@vencord/discord-types";
|
||||||
import { _resolveReady, filters, findByCodeLazy, findByPropsLazy, findLazy, mapMangledModuleLazy, waitFor } from "@webpack";
|
import { _resolveReady, filters, findByCodeLazy, findByPropsLazy, findLazy, mapMangledModuleLazy, waitFor } from "@webpack";
|
||||||
|
import type * as TSPattern from "ts-pattern";
|
||||||
|
|
||||||
export let FluxDispatcher: t.FluxDispatcher;
|
export let FluxDispatcher: t.FluxDispatcher;
|
||||||
waitFor(["dispatch", "subscribe"], m => {
|
waitFor(["dispatch", "subscribe"], m => {
|
||||||
|
|
@ -51,7 +52,7 @@ export const useDrag = findByCodeLazy("useDrag::spec.begin was deprecated");
|
||||||
// you cant make a better finder i love that they remove display names sm
|
// you cant make a better finder i love that they remove display names sm
|
||||||
export const useDrop = findByCodeLazy(".options);return", ".collect,");
|
export const useDrop = findByCodeLazy(".options);return", ".collect,");
|
||||||
|
|
||||||
export const { match, P }: Pick<typeof import("ts-pattern"), "match" | "P"> = mapMangledModuleLazy("@ts-pattern/matcher", {
|
export const { match, P }: Pick<typeof TSPattern, "match" | "P"> = mapMangledModuleLazy("@ts-pattern/matcher", {
|
||||||
match: filters.byCode("return new"),
|
match: filters.byCode("return new"),
|
||||||
P: filters.byProps("when")
|
P: filters.byProps("when")
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue