mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-08 06:03:03 -04:00
Krystal😠
This commit is contained in:
parent
f00748918c
commit
334ce7c113
5 changed files with 123 additions and 64 deletions
|
@ -122,7 +122,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
|
|||
- SekaiStickers by MaiKokain
|
||||
- ServerSearch by camila314
|
||||
- ShowBadgesInChat by Inbestigator & KrystalSkull
|
||||
- Signature by KrystalSkull
|
||||
- Signature by Ven, Rini, ImBanana, KrystalSkull
|
||||
- SidebarChat by Joona
|
||||
- StatsfmRPC by Crxaw & vmohammad
|
||||
- Slap by Korbo
|
||||
|
|
|
@ -13,6 +13,12 @@ export const enum RenderType {
|
|||
BACKGROUND,
|
||||
}
|
||||
|
||||
export const enum BlockDisplayType {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
BOTH
|
||||
}
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
renderType: {
|
||||
type: OptionType.SELECT,
|
||||
|
@ -32,6 +38,33 @@ export const settings = definePluginSettings({
|
|||
value: RenderType.BACKGROUND
|
||||
},
|
||||
]
|
||||
},
|
||||
enableShortHexCodes: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Enable 3 char hex-code like #39f",
|
||||
default: true,
|
||||
// Regex are created on the start, so without restart nothing would change
|
||||
restartNeeded: true
|
||||
},
|
||||
blockView: {
|
||||
type: OptionType.SELECT,
|
||||
disabled: () => settings.store.renderType !== RenderType.BLOCK,
|
||||
description: "Where to display colored block",
|
||||
options: [
|
||||
{
|
||||
label: "Right side",
|
||||
value: BlockDisplayType.RIGHT,
|
||||
default: true
|
||||
},
|
||||
{
|
||||
label: "Left side",
|
||||
value: BlockDisplayType.LEFT
|
||||
},
|
||||
{
|
||||
label: "Both sides",
|
||||
value: BlockDisplayType.BOTH
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -59,5 +92,4 @@ export const regex = [
|
|||
{ reg: /rgb\(\v\c\v\c\v\)/g, type: ColorType.RGB },
|
||||
{ reg: /rgba\(\v\c\v\c\v(\c|\/?)\s*\f\)/g, type: ColorType.RGBA },
|
||||
{ reg: /hsl\(\v°?\c\s*?\d+%?\s*?\c\s*?\d+%?\s*?\)/g, type: ColorType.HSL },
|
||||
{ reg: /#(?:[0-9a-fA-F]{3}){1,2}/g, type: ColorType.HEX }
|
||||
].map(v => { v.reg = replaceRegexp(v.reg.source); return v; });
|
||||
|
|
|
@ -6,20 +6,14 @@
|
|||
|
||||
import "./styles.css";
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import definePlugin, { StartAt } from "@utils/types";
|
||||
import { React } from "@webpack/common";
|
||||
import type { ReactElement } from "react";
|
||||
|
||||
import {
|
||||
ColorType,
|
||||
regex,
|
||||
RenderType,
|
||||
replaceRegexp,
|
||||
settings,
|
||||
} from "./constants";
|
||||
import { BlockDisplayType, ColorType, regex, RenderType, replaceRegexp, settings } from "./constants";
|
||||
|
||||
const source = regex.map(r => r.reg.source).join("|");
|
||||
const matchAllRegExp = new RegExp(`^(${source})`, "i");
|
||||
|
||||
interface ParsedColorInfo {
|
||||
type: "color";
|
||||
|
@ -28,10 +22,7 @@ interface ParsedColorInfo {
|
|||
text: string;
|
||||
}
|
||||
|
||||
const requiredFirstCharacters = ["r", "h", "#"].flatMap(v => [
|
||||
v,
|
||||
v.toUpperCase(),
|
||||
]);
|
||||
const requiredFirstCharacters = ["r", "h", "#"].flatMap(v => [v, v.toUpperCase()]);
|
||||
|
||||
export default definePlugin({
|
||||
authors: [EquicordDevs.Hen],
|
||||
|
@ -46,8 +37,8 @@ export default definePlugin({
|
|||
group: true,
|
||||
replacement: {
|
||||
match: /roleMention:\{order:(\i\.\i\.order)/,
|
||||
replace: "color:$self.getColor($1),$&",
|
||||
},
|
||||
replace: "color:$self.getColor($1),$&"
|
||||
}
|
||||
},
|
||||
// Changes text md rule regex, so it stops right before hsl( | rgb(
|
||||
// Without it discord will try to pass a string without those to color rule
|
||||
|
@ -55,11 +46,19 @@ export default definePlugin({
|
|||
find: ".defaultRules.text,match:",
|
||||
group: true,
|
||||
replacement: {
|
||||
// $) don't match with a " after the )
|
||||
match: /\$\)(?!")/,
|
||||
// $)/)
|
||||
match: /\$\)\//,
|
||||
// hsl(|rgb(|$&
|
||||
replace: requiredFirstCharacters.join("|") + "|$&",
|
||||
},
|
||||
replace: requiredFirstCharacters.join("|") + "|$&"
|
||||
}
|
||||
},
|
||||
// Fix the issue with [#123](https://example.com) rendered as plain text
|
||||
{
|
||||
find: "parseInlineCodeChildContent:",
|
||||
replacement: {
|
||||
match: /parseInlineCodeChildContent:/,
|
||||
replace: "isInsideOfLink:true,$&"
|
||||
}
|
||||
},
|
||||
// Discord just requires it to be here
|
||||
// Or it explodes (bad)
|
||||
|
@ -68,11 +67,23 @@ export default definePlugin({
|
|||
group: true,
|
||||
replacement: {
|
||||
match: /roleMention:{type:/,
|
||||
replace: 'color:{type:"inlineObject"},$&',
|
||||
},
|
||||
replace: "color:{type:\"inlineObject\"},$&",
|
||||
}
|
||||
},
|
||||
],
|
||||
start() {
|
||||
const amount = settings.store.enableShortHexCodes ? "{1,2}" : "{2}";
|
||||
regex.push({
|
||||
reg: new RegExp("#(?:[0-9a-fA-F]{3})" + amount, "g"),
|
||||
type: ColorType.HEX
|
||||
});
|
||||
},
|
||||
// Needed to load all regex before patching
|
||||
startAt: StartAt.Init,
|
||||
getColor(order: number) {
|
||||
const source = regex.map(r => r.reg.source).join("|");
|
||||
const matchAllRegExp = new RegExp(`^(${source})`, "i");
|
||||
|
||||
return {
|
||||
order,
|
||||
// Don't even try to match if the message chunk doesn't start with...
|
||||
|
@ -82,20 +93,16 @@ export default definePlugin({
|
|||
match(content: string) {
|
||||
return matchAllRegExp.exec(content);
|
||||
},
|
||||
parse(
|
||||
matchedContent: RegExpExecArray,
|
||||
_,
|
||||
parseProps: Record<string, any>,
|
||||
): ParsedColorInfo | { type: "text"; content: string; } {
|
||||
parse(matchedContent: RegExpExecArray, _, parseProps: Record<string, any>):
|
||||
ParsedColorInfo | ({ type: "text", content: string; }) {
|
||||
// This check makes sure that it doesn't try to parse color
|
||||
// When typing/editing message
|
||||
//
|
||||
// Discord doesn't know how to deal with color and crashes
|
||||
if (!parseProps.messageId)
|
||||
return {
|
||||
type: "text",
|
||||
content: matchedContent[0],
|
||||
};
|
||||
if (!parseProps.messageId || parseProps.isInsideOfLink) return {
|
||||
type: "text",
|
||||
content: matchedContent[0]
|
||||
};
|
||||
|
||||
const content = matchedContent[0];
|
||||
try {
|
||||
|
@ -105,44 +112,59 @@ export default definePlugin({
|
|||
type: "color",
|
||||
colorType: type,
|
||||
color: parseColor(content, type),
|
||||
text: content,
|
||||
text: content
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return {
|
||||
type: "text",
|
||||
content: matchedContent[0],
|
||||
content: matchedContent[0]
|
||||
};
|
||||
}
|
||||
},
|
||||
// react(args: ReturnType<typeof this.parse>)
|
||||
react({ text, colorType, color }: ParsedColorInfo) {
|
||||
react: ErrorBoundary.wrap(({ text, colorType, color }: ParsedColorInfo) => {
|
||||
if (settings.store.renderType === RenderType.FOREGROUND) {
|
||||
return <span style={{ color: color }}>{text}</span>;
|
||||
}
|
||||
const styles = {
|
||||
"--color": color,
|
||||
"--color": color
|
||||
} as React.CSSProperties;
|
||||
|
||||
if (settings.store.renderType === RenderType.BACKGROUND) {
|
||||
const isDark = isColorDark(color, colorType);
|
||||
const className = `vc-color-bg ${!isDark ? "vc-color-bg-invert" : ""}`;
|
||||
return (
|
||||
<span className={className} style={styles}>
|
||||
{text}
|
||||
</span>
|
||||
);
|
||||
return <span className={className} style={styles}>{text}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{text}
|
||||
<span className="vc-color-block" style={styles}></span>
|
||||
</>
|
||||
);
|
||||
},
|
||||
// Only block display left
|
||||
const margin = "2px";
|
||||
|
||||
switch (settings.store.blockView) {
|
||||
case BlockDisplayType.LEFT:
|
||||
styles.marginRight = margin;
|
||||
return <><span className="vc-color-block" style={styles} />{text}</>;
|
||||
|
||||
case BlockDisplayType.RIGHT:
|
||||
styles.marginLeft = margin;
|
||||
return <>{text}<span className="vc-color-block" style={styles} /></>;
|
||||
|
||||
case BlockDisplayType.BOTH:
|
||||
styles.marginLeft = margin;
|
||||
styles.marginRight = margin;
|
||||
return <>
|
||||
<span className="vc-color-block" style={styles} />
|
||||
{text}
|
||||
<span className="vc-color-block" style={styles} />
|
||||
</>;
|
||||
}
|
||||
}, {
|
||||
fallback: data => {
|
||||
const child = data.children as ReactElement<any>;
|
||||
return <>{child.props?.text}</>;
|
||||
}
|
||||
})
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// https://en.wikipedia.org/wiki/Relative_luminance
|
||||
|
@ -150,25 +172,32 @@ const calcRGBLightness = (r: number, g: number, b: number) => {
|
|||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
};
|
||||
const isColorDark = (color: string, type: ColorType): boolean => {
|
||||
const border = 115;
|
||||
switch (type) {
|
||||
case ColorType.RGBA:
|
||||
case ColorType.RGB: {
|
||||
const match = color.match(/\d+/g)!;
|
||||
const lightness = calcRGBLightness(+match[0], +match[1], +match[2]);
|
||||
return lightness < 140;
|
||||
return lightness < border;
|
||||
}
|
||||
case ColorType.HEX: {
|
||||
var rgb = parseInt(color.substring(1), 16);
|
||||
color = color.substring(1);
|
||||
if (color.length === 3) {
|
||||
color = color.split("").flatMap(v => [v, v]).join("");
|
||||
}
|
||||
|
||||
const rgb = parseInt(color, 16);
|
||||
const r = (rgb >> 16) & 0xff;
|
||||
const g = (rgb >> 8) & 0xff;
|
||||
const b = (rgb >> 0) & 0xff;
|
||||
|
||||
const lightness = calcRGBLightness(r, g, b);
|
||||
return lightness < 140;
|
||||
return lightness < border;
|
||||
}
|
||||
case ColorType.HSL: {
|
||||
const match = color.match(/\d+/g)!;
|
||||
const lightness = +match[2];
|
||||
return lightness < 50;
|
||||
return lightness < (border / 255 * 100);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -184,10 +213,7 @@ const getColorType = (color: string): ColorType => {
|
|||
};
|
||||
|
||||
function parseColor(str: string, type: ColorType): string {
|
||||
str = str
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replaceAll(/(\s|,)+/g, " ");
|
||||
str = str.toLowerCase().trim().replaceAll(/(\s|,)+/g, " ");
|
||||
switch (type) {
|
||||
case ColorType.RGB:
|
||||
return str;
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
background: var(--color);
|
||||
height: 1rem;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 0.2rem;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
user-select: none;
|
||||
margin-left: 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vc-color-bg {
|
||||
|
@ -16,5 +17,5 @@
|
|||
/* Light color in dark theme */
|
||||
.theme-dark .vc-color-bg.vc-color-bg-invert,
|
||||
.theme-light .vc-color-bg:not(.vc-color-bg-invert) {
|
||||
color: var(--background-tertiary);
|
||||
color: var(--background-secondary);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption,
|
|||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { addMessagePreSendListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
||||
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import { Devs, EquicordDevs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Menu, React } from "@webpack/common";
|
||||
|
||||
|
@ -98,7 +98,7 @@ migratePluginSettings("Signature", "SentVia");
|
|||
export default definePlugin({
|
||||
name: "Signature",
|
||||
description: "Automated fingerprint/end text",
|
||||
authors: [EquicordDevs.KrystalSkull],
|
||||
authors: [Devs.Ven, Devs.Rini, Devs.ImBanana, EquicordDevs.KrystalSkull],
|
||||
dependencies: ["MessageEventsAPI", "ChatInputButtonAPI"],
|
||||
|
||||
start: () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue