mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-10 09:56:24 +00:00
add support forr user statuses and onboarding
This commit is contained in:
parent
16a1c44947
commit
e139522fa7
1 changed files with 72 additions and 10 deletions
|
@ -24,12 +24,18 @@ import { Margins } from "@utils/margins";
|
|||
import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
||||
import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
|
||||
import { Constants, ContextMenuApi, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
|
||||
import { Promisable } from "type-fest";
|
||||
|
||||
const StickersStore = findStoreLazy("StickersStore");
|
||||
const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START");
|
||||
|
||||
interface OnboardingContextMenuProps {
|
||||
option: {
|
||||
emoji: { id: string; name: string; animated: boolean; } | { id: null; };
|
||||
};
|
||||
}
|
||||
|
||||
interface Sticker {
|
||||
t: "Sticker";
|
||||
description: string;
|
||||
|
@ -176,7 +182,6 @@ const getFontSize = (s: string) => {
|
|||
const sizes = [20, 20, 18, 18, 16, 14, 12];
|
||||
return sizes[s.length] ?? 4;
|
||||
};
|
||||
|
||||
const nameValidator = /^\w+$/i;
|
||||
|
||||
function CloneModal({ data }: { data: Sticker | Emoji; }) {
|
||||
|
@ -272,7 +277,11 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) {
|
|||
);
|
||||
}
|
||||
|
||||
function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable<Omit<Sticker | Emoji, "t">>) {
|
||||
type Discriminate<
|
||||
U extends { "t": string; },
|
||||
K extends U["t"]
|
||||
> = U extends { "t": K; } ? U : never;
|
||||
function buildMenuItem<T extends (Emoji | Sticker)["t"]>(type: T, fetchData: () => Promisable<Omit<Discriminate<Sticker | Emoji, T>, "t">>) {
|
||||
return (
|
||||
<Menu.MenuItem
|
||||
id="emote-cloner"
|
||||
|
@ -281,7 +290,7 @@ function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable<Om
|
|||
action={() =>
|
||||
openModalLazy(async () => {
|
||||
const res = await fetchData();
|
||||
const data = { t: type, ...res } as Sticker | Emoji;
|
||||
const data = { t: type, ...res } as any as Sticker | Emoji;
|
||||
const url = getUrl(data);
|
||||
|
||||
return modalProps => (
|
||||
|
@ -309,7 +318,7 @@ function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable<Om
|
|||
);
|
||||
}
|
||||
|
||||
function isGifUrl(url: string) {
|
||||
function isEmojiAnimated(url: string) {
|
||||
const u = new URL(url);
|
||||
return u.pathname.endsWith(".gif") || u.searchParams.get("animated") === "true";
|
||||
}
|
||||
|
@ -330,7 +339,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =
|
|||
return buildMenuItem("Emoji", () => ({
|
||||
id: favoriteableId,
|
||||
name,
|
||||
isAnimated: isGifUrl(itemHref ?? itemSrc)
|
||||
isAnimated: isEmojiAnimated(itemHref ?? itemSrc)
|
||||
}));
|
||||
case "sticker":
|
||||
const sticker = props.message.stickerItems.find(s => s.id === favoriteableId);
|
||||
|
@ -354,20 +363,73 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t
|
|||
children.push(buildMenuItem("Emoji", () => ({
|
||||
id,
|
||||
name,
|
||||
isAnimated: firstChild && isGifUrl(firstChild.src)
|
||||
isAnimated: firstChild && isEmojiAnimated(firstChild.src)
|
||||
})));
|
||||
} else if (type === "sticker" && !props.target.className?.includes("lottieCanvas")) {
|
||||
children.push(buildMenuItem("Sticker", () => fetchSticker(id)));
|
||||
}
|
||||
};
|
||||
let emojiUrlRegex: RegExp;
|
||||
// Patches user statuses with a custom emoji
|
||||
const imageContextMenuPatch: NavContextMenuPatchCallback = (children, { target, src }: {
|
||||
target?: HTMLImageElement;
|
||||
src?: string;
|
||||
}) => {
|
||||
const [, id] = src?.match(emojiUrlRegex) ?? [];
|
||||
|
||||
if (!id) return;
|
||||
|
||||
const name = target?.alt || "EmojiName";
|
||||
children.push(buildMenuItem("Emoji", () => ({
|
||||
id,
|
||||
name,
|
||||
isAnimated: isEmojiAnimated(src!)
|
||||
})));
|
||||
return;
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "EmoteCloner",
|
||||
description: "Allows you to clone Emotes & Stickers to your own server (right click them)",
|
||||
tags: ["StickerCloner"],
|
||||
authors: [Devs.Ven, Devs.Nuckyz],
|
||||
authors: [Devs.Ven, Devs.Nuckyz, Devs.sadan],
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "emoji.animated||",
|
||||
replacement: {
|
||||
match: /(?=onClick:)/,
|
||||
replace: "onContextMenu:$self.OnboardingContextMenu.bind(null, arguments[0]),"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
start() {
|
||||
const { CDN_HOST } = window.GLOBAL_ENV;
|
||||
emojiUrlRegex = new RegExp(`^${location.protocol}//${CDN_HOST}/emojis/(\\d+)\\.\\w+.+$`);
|
||||
},
|
||||
|
||||
contextMenus: {
|
||||
"message": messageContextMenuPatch,
|
||||
"expression-picker": expressionPickerPatch
|
||||
}
|
||||
"expression-picker": expressionPickerPatch,
|
||||
"image-context": imageContextMenuPatch
|
||||
},
|
||||
|
||||
OnboardingContextMenu({ option: { emoji } }: OnboardingContextMenuProps, ev: React.MouseEvent) {
|
||||
// covers no emoji and unicode emojis
|
||||
if (emoji?.id == null) return;
|
||||
|
||||
console.log(emoji);
|
||||
ContextMenuApi.openContextMenuLazy(ev, async () => {
|
||||
return () => (<Menu.Menu
|
||||
navId="onboarding-question-context"
|
||||
onClose={() => FluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" })}
|
||||
>
|
||||
{buildMenuItem("Emoji", () => ({
|
||||
...emoji,
|
||||
isAnimated: emoji.animated
|
||||
}))}
|
||||
</Menu.Menu>);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue