SMYN: Support for nitro effects in DMs & limiting friend/custom names to DMs. (#764)
* Stuff. * I hate it here. * Clarify setting. * Fix Questify patch.
This commit is contained in:
parent
e268d3f252
commit
c88da3a6ab
3 changed files with 477 additions and 86 deletions
|
|
@ -1294,7 +1294,7 @@ export default definePlugin({
|
|||
find: ",{progressTextAnimation:",
|
||||
replacement: {
|
||||
match: /(?<=children:\i}=)(\i)/,
|
||||
replace: "Object.assign({},$1,$self.getQuestPanelPercentComplete($1))"
|
||||
replace: "Object.assign({},$1,$1.quest?$self.getQuestPanelPercentComplete($1):{})"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1302,7 +1302,7 @@ export default definePlugin({
|
|||
// useful information for Quests being auto-completed.
|
||||
find: '"progress-title"',
|
||||
replacement: {
|
||||
match: /(?<=return.{0,150}?quest:(\i),percentComplete:\i.{0,280}?"progress-title",children.{0,115}?children:)(\i.{0,50}"progress-subtitle",isTextTransition:!0,children.{0,115}?children:)/,
|
||||
match: /(?<={quest:(\i).{0,250}?return.{0,150}?,percentComplete:\i.{0,280}?"progress-title",children.{0,115}?children:)(\i.{0,50}"progress-subtitle",isTextTransition:!0,children.{0,115}?children:)/,
|
||||
replace: "$self.getQuestPanelTitleText($1)??$2$self.getQuestPanelSubtitleText($1)??"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,15 +13,19 @@ import { definePluginSettings } from "@api/Settings";
|
|||
import { Button, ErrorBoundary, Heading, TextButton } from "@components/index";
|
||||
import mentionAvatars from "@plugins/mentionAvatars";
|
||||
import { Devs, EquicordDevs } from "@utils/constants";
|
||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/index";
|
||||
import { classNameFactory, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/index";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { GuildMember, Message, User } from "@vencord/discord-types";
|
||||
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
||||
import { ChannelStore, GuildMemberStore, GuildStore, Menu, MessageStore, RelationshipStore, StreamerModeStore, TextInput, useEffect, UserStore, useState } from "@webpack/common";
|
||||
import { ChannelStore, GuildMemberStore, GuildStore, Menu, MessageStore, RelationshipStore, StreamerModeStore, TextInput, useEffect, useState } from "@webpack/common";
|
||||
import { JSX } from "react";
|
||||
|
||||
const SMYNC = classNameFactory();
|
||||
const UserStore = findStoreLazy("UserStore");
|
||||
const wrapEmojis = findByCodeLazy("lastIndex;return");
|
||||
const adjustColor = findByCodeLazy("light1", "dark1", "toonStroke");
|
||||
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 roleColorPattern = /^role((?:\+|-)\d{0,4})?$/iu;
|
||||
const symbolPattern = /^[\p{S}\p{P}]{1,3}$/iu;
|
||||
|
|
@ -76,22 +80,14 @@ function validColor(color: string) {
|
|||
return isValid;
|
||||
}
|
||||
|
||||
function resolveColor(user: User | GuildMember, savedColor: string, fallbackColor: string, canUseGradient: boolean): any {
|
||||
const fallbackReturn = {
|
||||
normal: {
|
||||
original: {
|
||||
color: fallbackColor,
|
||||
"text-decoration-color": fallbackColor
|
||||
},
|
||||
adjusted: {
|
||||
color: fallbackColor,
|
||||
"text-decoration-color": fallbackColor
|
||||
}
|
||||
},
|
||||
gradient: null
|
||||
};
|
||||
|
||||
if (!savedColor.trim()) { return fallbackReturn; }
|
||||
function resolveColor(
|
||||
user: User | GuildMember,
|
||||
savedColor: string,
|
||||
canUseGradient: boolean,
|
||||
inGuild: boolean,
|
||||
forceWhite: boolean
|
||||
): Record<string, any> | null {
|
||||
if (!savedColor.trim()) { return null; }
|
||||
|
||||
let gradient: any = null;
|
||||
let primaryColor: any = savedColor;
|
||||
|
|
@ -103,18 +99,24 @@ function resolveColor(user: User | GuildMember, savedColor: string, fallbackColo
|
|||
|
||||
if (savedColor.toLowerCase().includes("role")) {
|
||||
const percentage = roleColorPattern.exec(savedColor)?.[1] || "";
|
||||
if (percentage && isNaN(parseInt(percentage))) return fallbackReturn;
|
||||
if (percentage && isNaN(parseInt(percentage))) return null;
|
||||
|
||||
const colorStrings = (user as any)?.colorStrings || {};
|
||||
primaryColor = colorStrings.primaryColor || null;
|
||||
secondaryColor = colorStrings.secondaryColor || null;
|
||||
tertiaryColor = colorStrings.tertiaryColor || null;
|
||||
const displayStyles = !inGuild ? (user as any)?.displayNameStyles || {} : {};
|
||||
|
||||
primaryColor = forceWhite ? "#ffffff" : colorStrings.primaryColor || displayStyles?.colors?.[0] || "#ffffff";
|
||||
if (typeof primaryColor === "number") primaryColor = `#${primaryColor.toString(16).padStart(6, "0")}`;
|
||||
|
||||
secondaryColor = forceWhite ? null : colorStrings.secondaryColor || displayStyles?.colors?.[1] || null;
|
||||
if (typeof secondaryColor === "number") secondaryColor = `#${secondaryColor.toString(16).padStart(6, "0")}`;
|
||||
|
||||
tertiaryColor = forceWhite ? null : colorStrings.tertiaryColor || displayStyles?.colors?.[2] || null;
|
||||
if (typeof tertiaryColor === "number") tertiaryColor = `#${tertiaryColor.toString(16).padStart(6, "0")}`;
|
||||
|
||||
primaryAdjusted = primaryColor;
|
||||
secondaryAdjusted = secondaryColor;
|
||||
tertiaryAdjusted = tertiaryColor;
|
||||
|
||||
if (!primaryColor) { return fallbackReturn; }
|
||||
|
||||
if (primaryColor && percentage) {
|
||||
primaryAdjusted = adjustHex(primaryColor, parseInt(percentage));
|
||||
}
|
||||
|
|
@ -128,7 +130,7 @@ function resolveColor(user: User | GuildMember, savedColor: string, fallbackColo
|
|||
}
|
||||
}
|
||||
|
||||
gradient = !canUseGradient || !secondaryColor
|
||||
gradient = !canUseGradient || !secondaryColor || forceWhite
|
||||
? null
|
||||
: tertiaryColor
|
||||
? "linear-gradient(to right,var(--custom-gradient-color-1),var(--custom-gradient-color-2),var(--custom-gradient-color-3),var(--custom-gradient-color-1))"
|
||||
|
|
@ -160,7 +162,7 @@ function resolveColor(user: User | GuildMember, savedColor: string, fallbackColo
|
|||
"--custom-gradient-color-2": secondaryColor || primaryColor,
|
||||
"--custom-gradient-color-3": tertiaryColor || primaryColor,
|
||||
"background-image": gradient,
|
||||
"animation": "show-me-your-name-animation 1.5s linear infinite"
|
||||
"animation": "smyn-animation 1.5s linear infinite"
|
||||
},
|
||||
static: {
|
||||
original: {
|
||||
|
|
@ -227,7 +229,14 @@ function validTemplate(value: string) {
|
|||
}
|
||||
}
|
||||
|
||||
function getProcessedNames(author: any, truncateAllNamesWithStreamerMode: boolean, discriminators: boolean): {
|
||||
function getProcessedNames(
|
||||
author: any,
|
||||
truncateAllNamesWithStreamerMode: boolean,
|
||||
discriminators: boolean,
|
||||
inGuild: boolean,
|
||||
friendNameOnlyInDirectMessages: boolean,
|
||||
customNameOnlyInDirectMessages: boolean
|
||||
): {
|
||||
username: string | null;
|
||||
display: string | null;
|
||||
nick: string | null;
|
||||
|
|
@ -263,13 +272,13 @@ function getProcessedNames(author: any, truncateAllNamesWithStreamerMode: boolea
|
|||
? author.nick[0] + "..."
|
||||
: author.nick as string;
|
||||
|
||||
const friendName: string | null = author ? RelationshipStore.getNickname(author.id) || null : null;
|
||||
const friendName: string | null = (author && !(inGuild && friendNameOnlyInDirectMessages)) ? RelationshipStore.getNickname(author.id) || null : null;
|
||||
const friend: string | null = !friendName ? null
|
||||
: StreamerModeStore.enabled && (truncateAllNamesWithStreamerMode || friendName.toLowerCase() === author.username.toLowerCase())
|
||||
? friendName[0] + "..."
|
||||
: friendName as string;
|
||||
|
||||
const customName: string | null = !author?.id ? null : customNicknames[author.id] || null;
|
||||
const customName: string | null = (author && !(inGuild && customNameOnlyInDirectMessages)) ? customNicknames[author.id] || null : null;
|
||||
const custom: string | null = !customName ? null
|
||||
: StreamerModeStore.enabled && (truncateAllNamesWithStreamerMode || customName.toLowerCase() === author.username.toLowerCase())
|
||||
? customName[0] + "..."
|
||||
|
|
@ -311,7 +320,7 @@ function getMemberListProfilesReactionsVoiceName(
|
|||
const member = guildId && user ? GuildMemberStore.getMember(guildId, user.id) : null;
|
||||
const author = user && member ? { ...user, ...member } : user || member || null;
|
||||
const shouldHookless = type === "reactionsTooltip" || type === "profilesTooltip";
|
||||
return renderUsername(author, null, null, type, "", shouldHookless);
|
||||
return renderUsername(author, null, null, type, "", shouldHookless, !!guildId);
|
||||
}
|
||||
|
||||
function getMemberListProfilesReactionsVoiceNameText(props: memberListProfileReactionProps): string | null {
|
||||
|
|
@ -332,7 +341,7 @@ function getMessageName(props: messageProps): [string | null, JSX.Element | null
|
|||
const member = isWebhook ? null : target && channel ? GuildMemberStore.getMember(channel.guild_id, target.id) : null;
|
||||
const author = user && member ? { ...user, ...member } : user || member || null;
|
||||
const mentionSymbol = hideDefaultAtSign && (!isRepliedMessage || replies) ? "" : withMentionPrefix ? "@" : "";
|
||||
return renderUsername(author, channel?.id || null, message?.id || null, isRepliedMessage ? "replies" : "messages", mentionSymbol);
|
||||
return renderUsername(author, channel?.id || null, message?.id || null, isRepliedMessage ? "replies" : "messages", mentionSymbol, false, !!channel?.guild_id);
|
||||
}
|
||||
|
||||
function getMessageNameElement(props: messageProps): JSX.Element | null {
|
||||
|
|
@ -343,7 +352,7 @@ function getMessageNameText(props: messageProps): string | null {
|
|||
return getMessageName(props)[0];
|
||||
}
|
||||
|
||||
export function getMentionNameElement(props: mentionProps): JSX.Element | null {
|
||||
function getMentionNameElement(props: mentionProps): JSX.Element | null {
|
||||
const { hideDefaultAtSign, mentions } = settings.use(["hideDefaultAtSign", "mentions"]);
|
||||
const { channelId, userId, props: nestedProps } = props;
|
||||
const channel = channelId ? ChannelStore.getChannel(channelId) || null : null;
|
||||
|
|
@ -351,7 +360,43 @@ export function getMentionNameElement(props: mentionProps): JSX.Element | null {
|
|||
const member = channel ? GuildMemberStore.getMember(channel.guild_id, userId) : null;
|
||||
const author = user && member ? { ...user, ...member } : user || member || null;
|
||||
const mentionSymbol = hideDefaultAtSign && mentions ? "" : "@";
|
||||
return renderUsername(author, channelId || null, nestedProps?.messageId || null, "mentions", mentionSymbol)[1];
|
||||
return renderUsername(author, channelId || null, nestedProps?.messageId || null, "mentions", mentionSymbol, false, !!channel?.guild_id)[1];
|
||||
}
|
||||
|
||||
function getEffectType(effectId: number | null | undefined): string | null {
|
||||
switch (effectId) {
|
||||
case 1: return "solid";
|
||||
// Delegate gradient effect handling to the guild
|
||||
// gradient handler. This adds animation to DM
|
||||
// gradients which are usually static.
|
||||
// case 2: return "gradient";
|
||||
case 3: return "neon";
|
||||
case 4: return "toon";
|
||||
case 5: return "pop";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
function computeEffectCSSVars(styles: any): Record<string, string> {
|
||||
if (!styles?.colors?.length) return {};
|
||||
|
||||
const toHex = (n: number) => `#${(n >>> 0).toString(16).padStart(6, "0")}`;
|
||||
const primary = toHex(styles.colors[0]);
|
||||
const secondary = styles.colors.length > 1 ? toHex(styles.colors[1]) : primary;
|
||||
const adjusted = adjustColor(primary);
|
||||
|
||||
return {
|
||||
"--smyn-effect-main-color": adjusted.main,
|
||||
"--smyn-effect-gradient-start": primary,
|
||||
"--smyn-effect-gradient-end": secondary,
|
||||
"--smyn-effect-light-1": adjusted.light1,
|
||||
"--smyn-effect-light-2": adjusted.light2,
|
||||
"--smyn-effect-dark-1": adjusted.dark1,
|
||||
"--smyn-effect-dark-2": adjusted.dark2,
|
||||
"--smyn-effect-neon-stroke": adjusted.neonStroke,
|
||||
"--smyn-effect-neon-flicker": `hsl(from ${adjusted.main} h calc(min(1, s) * ((s * 1.1) + 10)) 85)`,
|
||||
"--smyn-effect-toon-stroke": adjusted.toonStroke,
|
||||
};
|
||||
}
|
||||
|
||||
function renderUsername(
|
||||
|
|
@ -360,7 +405,8 @@ function renderUsername(
|
|||
messageId: string | null,
|
||||
type: "messages" | "replies" | "mentions" | "membersList" | "profilesPopout" | "profilesTooltip" | "reactionsTooltip" | "reactionsPopout" | "voiceChannel",
|
||||
mentionSymbol: string,
|
||||
hookless = false
|
||||
hookless: boolean,
|
||||
inGuild: boolean
|
||||
): [string | null, JSX.Element | null, string | null] {
|
||||
const isMessage = type === "messages";
|
||||
const isReply = type === "replies";
|
||||
|
|
@ -372,19 +418,44 @@ function renderUsername(
|
|||
const isReaction = isReactionsTooltip || isReactionsPopout;
|
||||
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", "customNameColor", "friendNameColor", "nicknameColor", "displayNameColor", "usernameColor", "nameSeparator", "triggerNameRerender"]);
|
||||
const { messages, replies, mentions, memberList, profilePopout, reactions, discriminators, hideDefaultAtSign, truncateAllNamesWithStreamerMode, removeDuplicates, ignoreGradients, ignoreFonts, animateGradients, includedNames, customNameColor, friendNameColor, nicknameColor, displayNameColor, usernameColor, nameSeparator, triggerNameRerender } = config;
|
||||
const config = hookless ? settings.store : settings.use(["messages", "replies", "mentions", "memberList", "profilePopout", "reactions", "friendNameOnlyInDirectMessages", "customNameOnlyInDirectMessages", "discriminators", "hideDefaultAtSign", "truncateAllNamesWithStreamerMode", "removeDuplicates", "ignoreGradients", "ignoreFonts", "animateGradients", "includedNames", "customNameColor", "friendNameColor", "nicknameColor", "displayNameColor", "usernameColor", "nameSeparator", "triggerNameRerender"]);
|
||||
const { messages, replies, mentions, memberList, profilePopout, reactions, friendNameOnlyInDirectMessages, customNameOnlyInDirectMessages, discriminators, truncateAllNamesWithStreamerMode, removeDuplicates, ignoreGradients, ignoreFonts, animateGradients, includedNames, customNameColor, friendNameColor, nicknameColor, displayNameColor, usernameColor, nameSeparator, triggerNameRerender } = config;
|
||||
|
||||
const channel = channelId ? ChannelStore.getChannel(channelId) || null : null;
|
||||
const message = channelId && messageId ? MessageStore.getMessage(channelId, messageId) : null;
|
||||
const groupId = (message as any)?.showMeYourNameGroupId || null;
|
||||
|
||||
const isHovering = (isMessage || isMention)
|
||||
? ((messageId && hoveringMessageMap.has(messageId)) || (groupId && hoveringMessageMap.has(groupId)))
|
||||
: isReply
|
||||
? (messageId && hoveringRepliesMap.has(messageId)) || (groupId && hoveringRepliesMap.has(groupId))
|
||||
: isReactionsPopout
|
||||
? hoveringReactionPopoutSet.has((author as User).id)
|
||||
: false;
|
||||
|
||||
const authorDisplayNameStyles = (!inGuild && (author as any)?.displayNameStyles) || null;
|
||||
const effectType = authorDisplayNameStyles ? getEffectType(authorDisplayNameStyles.effectId) : null;
|
||||
const effectCSSVars = authorDisplayNameStyles ? computeEffectCSSVars(authorDisplayNameStyles) : {};
|
||||
const hasEffect = !!effectType;
|
||||
const needsEffectDataAttr = effectType === "neon" || effectType === "toon" || effectType === "pop";
|
||||
const shouldShowEffect = hasEffect && isHovering;
|
||||
const shouldAnimateEffect = shouldShowEffect && !AccessibilityStore.useReducedMotion;
|
||||
const shouldUseDMDefault = !inGuild && !isHovering;
|
||||
|
||||
const canUseGradient = ((author as GuildMember)?.guildId ? (GuildStore.getGuild((author as GuildMember).guildId) ?? {}).premiumFeatures?.features.includes("ENHANCED_ROLE_COLORS") : !inGuild);
|
||||
const useTopRoleStyle = isMention || isReactionsPopout || channel?.isDM() || channel?.isGroupDM();
|
||||
const topRoleStyle = author ? resolveColor(author, "Role", canUseGradient, inGuild, shouldUseDMDefault) : null;
|
||||
const hasGradient = !!topRoleStyle?.gradient && Object.keys(topRoleStyle.gradient).length > 0;
|
||||
|
||||
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 options = splitTemplate(includedNames);
|
||||
const resolvedUsernameColor = author ? resolveColor(author, usernameColor.trim(), "", canUseGradient) : null;
|
||||
const resolvedDisplayNameColor = author ? resolveColor(author, displayNameColor.trim(), "", canUseGradient) : null;
|
||||
const resolvedNicknameColor = author ? resolveColor(author, nicknameColor.trim(), "", canUseGradient) : null;
|
||||
const resolvedFriendNameColor = author ? resolveColor(author, friendNameColor.trim(), "", canUseGradient) : null;
|
||||
const resolvedCustomNameColor = author ? resolveColor(author, customNameColor.trim(), "", canUseGradient) : null;
|
||||
const resolvedUsernameColor = author ? resolveColor(author, usernameColor.trim(), canUseGradient, inGuild, shouldUseDMDefault) : null;
|
||||
const resolvedDisplayNameColor = author ? resolveColor(author, displayNameColor.trim(), canUseGradient, inGuild, shouldUseDMDefault) : null;
|
||||
const resolvedNicknameColor = author ? resolveColor(author, nicknameColor.trim(), canUseGradient, inGuild, shouldUseDMDefault) : null;
|
||||
const resolvedFriendNameColor = author ? resolveColor(author, friendNameColor.trim(), canUseGradient, inGuild, shouldUseDMDefault) : null;
|
||||
const resolvedCustomNameColor = author ? resolveColor(author, customNameColor.trim(), canUseGradient, inGuild, shouldUseDMDefault) : null;
|
||||
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, custom } = getProcessedNames(author, truncateAllNamesWithStreamerMode, discriminators);
|
||||
const { username, display, nick, friend, custom } = getProcessedNames(author, truncateAllNamesWithStreamerMode, discriminators, inGuild, friendNameOnlyInDirectMessages, customNameOnlyInDirectMessages);
|
||||
|
||||
const names: Record<string, [string | null, object | null]> = {
|
||||
user: [username, resolvedUsernameColor],
|
||||
|
|
@ -416,7 +487,7 @@ function renderUsername(
|
|||
}
|
||||
}
|
||||
|
||||
if (!chosenName || !chosenStyle) {
|
||||
if (!chosenName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -426,7 +497,7 @@ function renderUsername(
|
|||
wrapped: chosenName,
|
||||
type: chosenType,
|
||||
suffix: suffix || "",
|
||||
style: chosenStyle as React.CSSProperties
|
||||
style: chosenStyle
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -513,18 +584,6 @@ function renderUsername(
|
|||
fourth = remainingNames.shift();
|
||||
fifth = remainingNames.shift();
|
||||
|
||||
const useTopRoleStyle = isMention || isReactionsPopout;
|
||||
const topRoleStyle = resolveColor(author, "Role", "", canUseGradient);
|
||||
const hasGradient = !!topRoleStyle?.gradient && Object.keys(topRoleStyle.gradient).length > 0;
|
||||
const message = channelId && messageId ? MessageStore.getMessage(channelId, messageId) : null;
|
||||
const groupId = (message as any)?.showMeYourNameGroupId || null;
|
||||
|
||||
const isHovering = (isMessage || isReply || isMention)
|
||||
? ((messageId && hoveringMessageMap.has(messageId)) || (groupId && hoveringMessageMap.has(groupId)))
|
||||
: isReactionsPopout
|
||||
? hoveringReactionPopoutSet.has((author as User).id)
|
||||
: false;
|
||||
|
||||
const shouldGradientGlow = isHovering && hasGradient;
|
||||
const shouldAnimateGradients = shouldGradientGlow && !AccessibilityStore.useReducedMotion;
|
||||
const shouldAnimateSecondaryNames = animateGradients && !ignoreGradients;
|
||||
|
|
@ -560,21 +619,34 @@ function renderUsername(
|
|||
...(isReactionsPopout
|
||||
? { display: "flex", flexWrap: "wrap", lineHeight: "1.1em", fontSize: "0.9em" }
|
||||
: {}),
|
||||
...(hasEffect ? effectCSSVars : {})
|
||||
} as React.CSSProperties;
|
||||
|
||||
const nameElement = (
|
||||
<span style={topLevelStyle} className="show-me-your-name-container">
|
||||
<span
|
||||
style={{
|
||||
...topLevelStyle,
|
||||
...(topRoleStyle?.normal.original || {})
|
||||
}}
|
||||
className="show-me-your-name-container"
|
||||
>
|
||||
{mentionSymbol && <span>{mentionSymbol}</span>}
|
||||
{(
|
||||
<span
|
||||
className={(shouldGradientGlow ? (gradientClasses + " " + firstGroupClasses) : firstGroupClasses)}
|
||||
className={SMYNC(firstGroupClasses, { [gradientClasses]: shouldGradientGlow })}
|
||||
data-text={shouldGradientGlow ? firstDataText : undefined}
|
||||
style={(shouldGradientGlow && useTopRoleStyle && topRoleStyle ? topRoleStyle.gradient.animated : undefined) as React.CSSProperties}
|
||||
>
|
||||
<span
|
||||
className={firstNameClasses}
|
||||
style={
|
||||
topRoleStyle ?
|
||||
className={SMYNC(firstNameClasses, {
|
||||
"smyn-effect-container": shouldShowEffect,
|
||||
[`smyn-effect-${effectType}`]: shouldShowEffect,
|
||||
"smyn-effect-animated": shouldAnimateEffect
|
||||
})}
|
||||
data-username-with-effects={needsEffectDataAttr && shouldShowEffect ? first.name : undefined}
|
||||
style={shouldShowEffect
|
||||
? undefined
|
||||
: topRoleStyle ?
|
||||
shouldAnimateGradients && topRoleStyle.gradient
|
||||
? topRoleStyle.gradient.animated
|
||||
: topRoleStyle.gradient
|
||||
|
|
@ -593,7 +665,7 @@ function renderUsername(
|
|||
].map(({ name, dataText, groupClass, nameClass, position }) => name && (
|
||||
<span
|
||||
key={position}
|
||||
className={(shouldGradientGlow && shouldAnimateSecondaryNames ? (gradientClasses + " " + groupClass) : groupClass)}
|
||||
className={SMYNC(groupClass, { [gradientClasses]: shouldGradientGlow && shouldAnimateSecondaryNames })}
|
||||
data-text={shouldGradientGlow && dataText ? dataText : undefined}
|
||||
style={(shouldGradientGlow && shouldAnimateSecondaryNames ? name.style.gradient.animated : undefined) as React.CSSProperties}
|
||||
>
|
||||
|
|
@ -601,17 +673,24 @@ function renderUsername(
|
|||
<span>{nameSeparator}</span>
|
||||
{name.prefix}</span>
|
||||
<span
|
||||
// On non-primary names, allow disabling the gradients completely, or just their animation & glow.
|
||||
className={nameClass}
|
||||
// On non-primary names, allow disabling the effects completely, or just their animation & glow.
|
||||
className={SMYNC(nameClass, {
|
||||
"smyn-effect-container": shouldShowEffect && !ignoreGradients,
|
||||
[`smyn-effect-${effectType}`]: shouldShowEffect && !ignoreGradients,
|
||||
"smyn-effect-animated": shouldAnimateEffect && shouldAnimateSecondaryNames
|
||||
})}
|
||||
data-username-with-effects={needsEffectDataAttr && shouldShowEffect && !ignoreGradients ? name.name : undefined}
|
||||
style={{
|
||||
...(ignoreFonts ? { "font-family": "var(--font-primary)", "letter-spacing": "normal" } : {}),
|
||||
...(ignoreGradients
|
||||
? name.style.normal.adjusted
|
||||
: shouldAnimateGradients && shouldAnimateSecondaryNames && name.style.gradient
|
||||
? name.style.gradient.animated
|
||||
: name.style.gradient
|
||||
? name.style.gradient.static.original
|
||||
: name.style.normal.adjusted)
|
||||
...(name.style
|
||||
? ignoreGradients
|
||||
? name.style.normal.adjusted
|
||||
: shouldAnimateGradients && shouldAnimateSecondaryNames && name.style.gradient
|
||||
? name.style.gradient.animated
|
||||
: name.style.gradient
|
||||
? name.style.gradient.static.original
|
||||
: name.style.normal.adjusted
|
||||
: {})
|
||||
}}>
|
||||
{name.wrapped}</span>
|
||||
<span style={affixColor as React.CSSProperties} className={suffixClasses}>
|
||||
|
|
@ -625,10 +704,12 @@ function renderUsername(
|
|||
}
|
||||
|
||||
const hoveringMessageMap = new Map<string, number>();
|
||||
const hoveringRepliesMap = new Map<string, number>();
|
||||
const hoveringReactionPopoutSet = new Set<string>();
|
||||
|
||||
function handleHoveringMessage(message: any, isHovering: boolean) {
|
||||
const messageId = message?.id;
|
||||
const repliedId = message?.messageReference?.message_id;
|
||||
const groupId = message?.showMeYourNameGroupId ?? "";
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -637,9 +718,11 @@ function handleHoveringMessage(message: any, isHovering: boolean) {
|
|||
if (isHovering) {
|
||||
addHoveringMessage(messageId);
|
||||
addHoveringMessage(groupId);
|
||||
addHoveringReply(repliedId);
|
||||
} else {
|
||||
removeHoveringMessage(messageId);
|
||||
removeHoveringMessage(groupId);
|
||||
removeHoveringReply(repliedId);
|
||||
}
|
||||
}, [messageId, groupId, isHovering]);
|
||||
}
|
||||
|
|
@ -668,6 +751,30 @@ function removeHoveringMessage(id: string) {
|
|||
}
|
||||
}
|
||||
|
||||
function addHoveringReply(id: string) {
|
||||
if (!id) return;
|
||||
|
||||
const currentCount = hoveringRepliesMap.get(id) || 0;
|
||||
hoveringRepliesMap.set(id, currentCount + 1);
|
||||
|
||||
if (currentCount === 0) {
|
||||
settings.store.triggerNameRerender = !settings.store.triggerNameRerender;
|
||||
}
|
||||
}
|
||||
|
||||
function removeHoveringReply(id: string) {
|
||||
if (!id) return;
|
||||
|
||||
const currentCount = hoveringRepliesMap.get(id) || 0;
|
||||
|
||||
if (currentCount <= 1) {
|
||||
hoveringRepliesMap.delete(id);
|
||||
settings.store.triggerNameRerender = !settings.store.triggerNameRerender;
|
||||
} else {
|
||||
hoveringRepliesMap.set(id, currentCount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
function addHoveringReactionPopout(id: string) {
|
||||
hoveringReactionPopoutSet.add(id);
|
||||
settings.store.triggerNameRerender = !settings.store.triggerNameRerender;
|
||||
|
|
@ -789,7 +896,7 @@ const settings = definePluginSettings({
|
|||
memberList: {
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true,
|
||||
description: "Display the first available name listed in your custom name format in the member list.",
|
||||
description: "Display the first available name listed in your custom name format in the member list and DMs list.",
|
||||
},
|
||||
profilePopout: {
|
||||
type: OptionType.BOOLEAN,
|
||||
|
|
@ -834,18 +941,28 @@ const settings = definePluginSettings({
|
|||
ignoreGradients: {
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true,
|
||||
description: "For the non-primary names, if the role has a gradient, ignore it in favor of the color set below.",
|
||||
description: "For the non-primary names, if the role has a gradient or nitro effect, ignore it in favor of the color set below.",
|
||||
},
|
||||
animateGradients: {
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
description: "For the non-primary 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 or nitro effect, animate it. This is disabled by \"Ignore Gradients\" and reduced motion.",
|
||||
},
|
||||
nameSeparator: {
|
||||
type: OptionType.STRING,
|
||||
description: "The separator to use between names. The default is a single space.",
|
||||
default: " ",
|
||||
},
|
||||
friendNameOnlyInDirectMessages: {
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
description: "Only display friend names when in DMs, and not in servers.",
|
||||
},
|
||||
customNameOnlyInDirectMessages: {
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
description: "Only display custom names when in DMs, and not in servers.",
|
||||
},
|
||||
includedNames: {
|
||||
type: OptionType.STRING,
|
||||
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.",
|
||||
|
|
@ -898,6 +1015,8 @@ export default definePlugin({
|
|||
isModified: true,
|
||||
settings,
|
||||
|
||||
UserStore,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: '="SYSTEM_TAG"',
|
||||
|
|
@ -923,6 +1042,14 @@ export default definePlugin({
|
|||
replace: "$self.getMemberListProfilesReactionsVoiceNameText({...arguments[0],type:\"membersList\"})??"
|
||||
},
|
||||
},
|
||||
{
|
||||
// Replace name in solo DM title bar and tooltip.
|
||||
find: "channel.isSystemDM(),",
|
||||
replacement: {
|
||||
match: /(?<=}\);)(return.{0,500}?{text:)(\i,position:"bottom",children:.{0,40}?children:)(\i\?\?\i.\i.getName\(\i\))/,
|
||||
replace: "const smynName=arguments[0].channel.recipients.length===1?$self.getMemberListProfilesReactionsVoiceNameText({user:$self.UserStore.getUser(arguments[0].channel.recipients[0]),type:\"profilesPopout\"})??null:null;$1smynName??$2smynName??$3"
|
||||
},
|
||||
},
|
||||
{
|
||||
// Track hovering on messages to animate gradients.
|
||||
// Attach the group ID to their messages to allow animating gradients within a group.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
@keyframes show-me-your-name-animation {
|
||||
/* stylelint-disable rule-empty-line-before */
|
||||
/* stylelint-disable property-no-vendor-prefix */
|
||||
|
||||
@keyframes smyn-animation {
|
||||
0% {
|
||||
background-position: 0;
|
||||
}
|
||||
|
|
@ -8,12 +11,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.show-me-your-name-gradient {
|
||||
.smyn-gradient {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.show-me-your-name-gradient::after {
|
||||
.smyn-gradient::after {
|
||||
background-clip: text;
|
||||
content: attr(data-text) / "";
|
||||
inset: 0;
|
||||
|
|
@ -26,25 +29,286 @@
|
|||
z-index: -1;
|
||||
}
|
||||
|
||||
.show-me-your-name-gradient-unset-bg::after {
|
||||
.smyn-gradient-unset-bg::after {
|
||||
background: unset;
|
||||
}
|
||||
|
||||
.show-me-your-name-gradient-inherit-bg::after {
|
||||
.smyn-gradient-inherit-bg::after {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
.show-me-your-name-gradient-hovered::after {
|
||||
.smyn-gradient-hovered::after {
|
||||
opacity: .7;
|
||||
transition: opacity .1s ease-in-out
|
||||
transition: opacity .1s ease-in-out;
|
||||
}
|
||||
|
||||
.show-me-your-name-modal-footer-container button {
|
||||
.smyn-modal-footer-container button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.show-me-your-name-reset-button {
|
||||
.smyn-reset-button {
|
||||
margin-top: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.smyn-container:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.smyn-effect-container {
|
||||
position: relative;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.smyn-effect-solid {
|
||||
color: var(--smyn-effect-main-color);
|
||||
}
|
||||
|
||||
.smyn-effect-gradient {
|
||||
background: linear-gradient(to bottom right, var(--smyn-effect-gradient-start) 10%, var(--smyn-effect-gradient-end) 90%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
background-size: 100% auto;
|
||||
-webkit-text-fill-color: transparent;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.smyn-effect-neon {
|
||||
paint-order: stroke fill;
|
||||
-webkit-text-stroke-width: calc(1px + .04em);
|
||||
-webkit-text-stroke-color: var(--smyn-effect-neon-stroke);
|
||||
-webkit-text-fill-color: currentcolor;
|
||||
color: var(--white);
|
||||
margin-inline-start: calc(-1px - .04em);
|
||||
margin-bottom: calc(-1px - .04em);
|
||||
padding-bottom: calc(1px + .04em);
|
||||
padding-inline-start: calc(1px + .04em);
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.smyn-effect-neon::after {
|
||||
content: attr(data-username-with-effects);
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(to bottom left, var(--smyn-effect-light-2) 0, var(--smyn-effect-light-2) 6%, var(--smyn-effect-main-color) 20%, var(--smyn-effect-light-1) 50%, var(--smyn-effect-light-2) 56%, var(--smyn-effect-main-color) 70%, var(--smyn-effect-light-1) 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
background-position: 100% 0;
|
||||
background-size: 200% 200%;
|
||||
-webkit-text-fill-color: transparent;
|
||||
color: var(--smyn-effect-main-color);
|
||||
filter: blur(calc(1px + .12em));
|
||||
opacity: 0;
|
||||
transition: opacity .15s ease-in-out;
|
||||
-webkit-text-stroke-width: calc(1px + .04em);
|
||||
-webkit-text-stroke-color: transparent;
|
||||
perspective: 1px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.smyn-effect-animated.smyn-effect-neon {
|
||||
animation: smyn-neon-flicker 4s cubic-bezier(.24, .31, .36, .93) infinite;
|
||||
animation-direction: normal;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.smyn-effect-animated.smyn-effect-neon::after {
|
||||
opacity: .8;
|
||||
animation: smyn-neon-glow-flicker 1666ms linear infinite;
|
||||
animation-direction: normal;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.smyn-effect-toon {
|
||||
--smyn-toon-stroke-width: calc(1.6px + 0.04em);
|
||||
--smyn-toon-margin: calc(var(--smyn-toon-stroke-width)*-1);
|
||||
|
||||
paint-order: stroke fill;
|
||||
position: relative;
|
||||
-webkit-text-stroke-width: var(--smyn-toon-stroke-width);
|
||||
-webkit-text-stroke-color: var(--smyn-effect-toon-stroke);
|
||||
color: var(--smyn-effect-toon-stroke);
|
||||
margin-inline: var(--smyn-toon-margin);
|
||||
margin-bottom: var(--smyn-toon-margin);
|
||||
padding-inline: var(--smyn-toon-stroke-width);
|
||||
padding-bottom: var(--smyn-toon-stroke-width);
|
||||
transition: color 266ms cubic-bezier(.43, .21, .27, .78);
|
||||
}
|
||||
|
||||
.smyn-effect-toon::before {
|
||||
background: linear-gradient(180deg, var(--white) 0, var(--smyn-effect-light-2) 8%, var(--smyn-effect-light-1) 15%, var(--smyn-effect-main-color) 25%, var(--smyn-effect-light-2) 45%, var(--smyn-effect-main-color) 55%, var(--white) 75%, var(--smyn-effect-light-2) 83%, var(--smyn-effect-light-1) 90%, var(--smyn-effect-main-color) 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
background-size: 100% 400%;
|
||||
content: attr(data-username-with-effects);
|
||||
inset: 0;
|
||||
padding-inline: var(--smyn-toon-stroke-width);
|
||||
padding-bottom: var(--smyn-toon-margin);
|
||||
position: absolute;
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-text-stroke-width: 0;
|
||||
-webkit-text-stroke-color: transparent;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: opacity 266ms cubic-bezier(.43, .21, .27, .78);
|
||||
}
|
||||
|
||||
.smyn-effect-pop {
|
||||
--smyn-pop-stroke-width: calc(1.2px + 0.04em);
|
||||
--smyn-pop-bottom-translate: 0.08em;
|
||||
|
||||
display: inline-block;
|
||||
color: var(--white);
|
||||
paint-order: stroke fill;
|
||||
position: relative;
|
||||
-webkit-text-stroke-color: var(--smyn-effect-dark-2);
|
||||
-webkit-text-stroke-width: var(--smyn-pop-stroke-width);
|
||||
margin-inline-start: calc(var(--smyn-pop-stroke-width)*-1);
|
||||
margin-bottom: calc(var(--smyn-pop-stroke-width)*-1 - var(--smyn-pop-bottom-translate));
|
||||
padding-bottom: calc(var(--smyn-pop-stroke-width) + var(--smyn-pop-bottom-translate));
|
||||
padding-inline-start: var(--smyn-pop-stroke-width);
|
||||
}
|
||||
|
||||
.smyn-effect-pop::before {
|
||||
bottom: calc(var(--smyn-pop-bottom-translate)*-1 - var(--smyn-pop-stroke-width));
|
||||
color: var(--smyn-effect-main-color);
|
||||
content: attr(data-username-with-effects);
|
||||
padding-inline-start: var(--smyn-pop-stroke-width);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: calc(100% - var(--smyn-pop-stroke-width));
|
||||
z-index: -1;
|
||||
-webkit-text-stroke-width: var(--smyn-pop-stroke-width);
|
||||
-webkit-text-stroke-color: transparent;
|
||||
background: linear-gradient(to bottom left, var(--smyn-effect-light-1) 0, var(--smyn-effect-light-1) 6%, var(--smyn-effect-main-color) 20%, var(--smyn-effect-main-color) 50%, var(--smyn-effect-light-1) 56%, var(--smyn-effect-main-color) 70%, var(--smyn-effect-main-color) 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
background-position: 100% 0;
|
||||
background-size: 200% 200%;
|
||||
transform: translate3d(0, var(--smyn-pop-bottom-translate), 0);
|
||||
-webkit-text-fill-color: transparent;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.smyn-effect-pop:hover::before {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: var(--smyn-effect-main-color);
|
||||
text-underline-offset: calc(var(--smyn-pop-bottom-translate));
|
||||
}
|
||||
|
||||
.smyn-effect-animated.smyn-effect-toon::before {
|
||||
animation: smyn-toon-animation 4s cubic-bezier(.44, .29, .48, 1) infinite;
|
||||
animation-direction: normal;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.smyn-effect-animated.smyn-effect-pop {
|
||||
animation: smyn-pop-main 4s cubic-bezier(.44, .29, .48, 1) infinite;
|
||||
animation-direction: normal;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.smyn-effect-animated.smyn-effect-pop::before {
|
||||
animation: smyn-pop-shadow 4s cubic-bezier(.44, .29, .48, 1) infinite;
|
||||
animation-direction: normal;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes smyn-neon-flicker {
|
||||
|
||||
0%,
|
||||
15%,
|
||||
18%,
|
||||
20%,
|
||||
23%,
|
||||
25%,
|
||||
50% {
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
16%,
|
||||
22%,
|
||||
28% {
|
||||
color: var(--smyn-effect-neon-flicker);
|
||||
}
|
||||
|
||||
51%,
|
||||
100% {
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes smyn-neon-glow-flicker {
|
||||
0% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 0 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes smyn-toon-animation {
|
||||
|
||||
0%,
|
||||
5% {
|
||||
background-position: 50% 0;
|
||||
}
|
||||
|
||||
55%,
|
||||
100% {
|
||||
background-position: 50% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes smyn-pop-main {
|
||||
0% {
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
18% {
|
||||
perspective: 1px;
|
||||
transform: translate3d(0, -.05em, 0);
|
||||
}
|
||||
|
||||
35% {
|
||||
perspective: 1px;
|
||||
transform: translate3d(0, .08em, 0);
|
||||
}
|
||||
|
||||
50%,
|
||||
100% {
|
||||
perspective: 1px;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes smyn-pop-shadow {
|
||||
0% {
|
||||
background-position: 100% 0;
|
||||
perspective: 1px;
|
||||
transform: translate3d(0, .08em, 0);
|
||||
}
|
||||
|
||||
18% {
|
||||
perspective: 1px;
|
||||
transform: translate3d(0, .13em, 0);
|
||||
}
|
||||
|
||||
35% {
|
||||
perspective: 1px;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
50%,
|
||||
100% {
|
||||
background-position: 0 100%;
|
||||
perspective: 1px;
|
||||
transform: translate3d(0, .08em, 0);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue