mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-10 18:06:22 +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 { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
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";
|
import { Promisable } from "type-fest";
|
||||||
|
|
||||||
const StickersStore = findStoreLazy("StickersStore");
|
const StickersStore = findStoreLazy("StickersStore");
|
||||||
const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START");
|
const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START");
|
||||||
|
|
||||||
|
interface OnboardingContextMenuProps {
|
||||||
|
option: {
|
||||||
|
emoji: { id: string; name: string; animated: boolean; } | { id: null; };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface Sticker {
|
interface Sticker {
|
||||||
t: "Sticker";
|
t: "Sticker";
|
||||||
description: string;
|
description: string;
|
||||||
|
@ -176,7 +182,6 @@ const getFontSize = (s: string) => {
|
||||||
const sizes = [20, 20, 18, 18, 16, 14, 12];
|
const sizes = [20, 20, 18, 18, 16, 14, 12];
|
||||||
return sizes[s.length] ?? 4;
|
return sizes[s.length] ?? 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
const nameValidator = /^\w+$/i;
|
const nameValidator = /^\w+$/i;
|
||||||
|
|
||||||
function CloneModal({ data }: { data: Sticker | Emoji; }) {
|
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 (
|
return (
|
||||||
<Menu.MenuItem
|
<Menu.MenuItem
|
||||||
id="emote-cloner"
|
id="emote-cloner"
|
||||||
|
@ -281,7 +290,7 @@ function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable<Om
|
||||||
action={() =>
|
action={() =>
|
||||||
openModalLazy(async () => {
|
openModalLazy(async () => {
|
||||||
const res = await fetchData();
|
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);
|
const url = getUrl(data);
|
||||||
|
|
||||||
return modalProps => (
|
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);
|
const u = new URL(url);
|
||||||
return u.pathname.endsWith(".gif") || u.searchParams.get("animated") === "true";
|
return u.pathname.endsWith(".gif") || u.searchParams.get("animated") === "true";
|
||||||
}
|
}
|
||||||
|
@ -330,7 +339,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =
|
||||||
return buildMenuItem("Emoji", () => ({
|
return buildMenuItem("Emoji", () => ({
|
||||||
id: favoriteableId,
|
id: favoriteableId,
|
||||||
name,
|
name,
|
||||||
isAnimated: isGifUrl(itemHref ?? itemSrc)
|
isAnimated: isEmojiAnimated(itemHref ?? itemSrc)
|
||||||
}));
|
}));
|
||||||
case "sticker":
|
case "sticker":
|
||||||
const sticker = props.message.stickerItems.find(s => s.id === favoriteableId);
|
const sticker = props.message.stickerItems.find(s => s.id === favoriteableId);
|
||||||
|
@ -354,20 +363,73 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t
|
||||||
children.push(buildMenuItem("Emoji", () => ({
|
children.push(buildMenuItem("Emoji", () => ({
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
isAnimated: firstChild && isGifUrl(firstChild.src)
|
isAnimated: firstChild && isEmojiAnimated(firstChild.src)
|
||||||
})));
|
})));
|
||||||
} else if (type === "sticker" && !props.target.className?.includes("lottieCanvas")) {
|
} else if (type === "sticker" && !props.target.className?.includes("lottieCanvas")) {
|
||||||
children.push(buildMenuItem("Sticker", () => fetchSticker(id)));
|
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({
|
export default definePlugin({
|
||||||
name: "EmoteCloner",
|
name: "EmoteCloner",
|
||||||
description: "Allows you to clone Emotes & Stickers to your own server (right click them)",
|
description: "Allows you to clone Emotes & Stickers to your own server (right click them)",
|
||||||
tags: ["StickerCloner"],
|
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: {
|
contextMenus: {
|
||||||
"message": messageContextMenuPatch,
|
"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