mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-08 14:13:01 -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
|
- SekaiStickers by MaiKokain
|
||||||
- ServerSearch by camila314
|
- ServerSearch by camila314
|
||||||
- ShowBadgesInChat by Inbestigator & KrystalSkull
|
- ShowBadgesInChat by Inbestigator & KrystalSkull
|
||||||
- Signature by KrystalSkull
|
- Signature by Ven, Rini, ImBanana, KrystalSkull
|
||||||
- SidebarChat by Joona
|
- SidebarChat by Joona
|
||||||
- StatsfmRPC by Crxaw & vmohammad
|
- StatsfmRPC by Crxaw & vmohammad
|
||||||
- Slap by Korbo
|
- Slap by Korbo
|
||||||
|
|
|
@ -13,6 +13,12 @@ export const enum RenderType {
|
||||||
BACKGROUND,
|
BACKGROUND,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum BlockDisplayType {
|
||||||
|
LEFT,
|
||||||
|
RIGHT,
|
||||||
|
BOTH
|
||||||
|
}
|
||||||
|
|
||||||
export const settings = definePluginSettings({
|
export const settings = definePluginSettings({
|
||||||
renderType: {
|
renderType: {
|
||||||
type: OptionType.SELECT,
|
type: OptionType.SELECT,
|
||||||
|
@ -32,6 +38,33 @@ export const settings = definePluginSettings({
|
||||||
value: RenderType.BACKGROUND
|
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: /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: /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: /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; });
|
].map(v => { v.reg = replaceRegexp(v.reg.source); return v; });
|
||||||
|
|
|
@ -6,20 +6,14 @@
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin, { StartAt } from "@utils/types";
|
||||||
import { React } from "@webpack/common";
|
import { React } from "@webpack/common";
|
||||||
|
import type { ReactElement } from "react";
|
||||||
|
|
||||||
import {
|
import { BlockDisplayType, ColorType, regex, RenderType, replaceRegexp, settings } from "./constants";
|
||||||
ColorType,
|
|
||||||
regex,
|
|
||||||
RenderType,
|
|
||||||
replaceRegexp,
|
|
||||||
settings,
|
|
||||||
} from "./constants";
|
|
||||||
|
|
||||||
const source = regex.map(r => r.reg.source).join("|");
|
|
||||||
const matchAllRegExp = new RegExp(`^(${source})`, "i");
|
|
||||||
|
|
||||||
interface ParsedColorInfo {
|
interface ParsedColorInfo {
|
||||||
type: "color";
|
type: "color";
|
||||||
|
@ -28,10 +22,7 @@ interface ParsedColorInfo {
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const requiredFirstCharacters = ["r", "h", "#"].flatMap(v => [
|
const requiredFirstCharacters = ["r", "h", "#"].flatMap(v => [v, v.toUpperCase()]);
|
||||||
v,
|
|
||||||
v.toUpperCase(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
authors: [EquicordDevs.Hen],
|
authors: [EquicordDevs.Hen],
|
||||||
|
@ -46,8 +37,8 @@ export default definePlugin({
|
||||||
group: true,
|
group: true,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /roleMention:\{order:(\i\.\i\.order)/,
|
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(
|
// 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
|
// 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:",
|
find: ".defaultRules.text,match:",
|
||||||
group: true,
|
group: true,
|
||||||
replacement: {
|
replacement: {
|
||||||
// $) don't match with a " after the )
|
// $)/)
|
||||||
match: /\$\)(?!")/,
|
match: /\$\)\//,
|
||||||
// hsl(|rgb(|$&
|
// 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
|
// Discord just requires it to be here
|
||||||
// Or it explodes (bad)
|
// Or it explodes (bad)
|
||||||
|
@ -68,11 +67,23 @@ export default definePlugin({
|
||||||
group: true,
|
group: true,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /roleMention:{type:/,
|
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) {
|
getColor(order: number) {
|
||||||
|
const source = regex.map(r => r.reg.source).join("|");
|
||||||
|
const matchAllRegExp = new RegExp(`^(${source})`, "i");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
order,
|
order,
|
||||||
// Don't even try to match if the message chunk doesn't start with...
|
// Don't even try to match if the message chunk doesn't start with...
|
||||||
|
@ -82,19 +93,15 @@ export default definePlugin({
|
||||||
match(content: string) {
|
match(content: string) {
|
||||||
return matchAllRegExp.exec(content);
|
return matchAllRegExp.exec(content);
|
||||||
},
|
},
|
||||||
parse(
|
parse(matchedContent: RegExpExecArray, _, parseProps: Record<string, any>):
|
||||||
matchedContent: RegExpExecArray,
|
ParsedColorInfo | ({ type: "text", content: string; }) {
|
||||||
_,
|
|
||||||
parseProps: Record<string, any>,
|
|
||||||
): ParsedColorInfo | { type: "text"; content: string; } {
|
|
||||||
// This check makes sure that it doesn't try to parse color
|
// This check makes sure that it doesn't try to parse color
|
||||||
// When typing/editing message
|
// When typing/editing message
|
||||||
//
|
//
|
||||||
// Discord doesn't know how to deal with color and crashes
|
// Discord doesn't know how to deal with color and crashes
|
||||||
if (!parseProps.messageId)
|
if (!parseProps.messageId || parseProps.isInsideOfLink) return {
|
||||||
return {
|
|
||||||
type: "text",
|
type: "text",
|
||||||
content: matchedContent[0],
|
content: matchedContent[0]
|
||||||
};
|
};
|
||||||
|
|
||||||
const content = matchedContent[0];
|
const content = matchedContent[0];
|
||||||
|
@ -105,44 +112,59 @@ export default definePlugin({
|
||||||
type: "color",
|
type: "color",
|
||||||
colorType: type,
|
colorType: type,
|
||||||
color: parseColor(content, type),
|
color: parseColor(content, type),
|
||||||
text: content,
|
text: content
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return {
|
return {
|
||||||
type: "text",
|
type: "text",
|
||||||
content: matchedContent[0],
|
content: matchedContent[0]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// react(args: ReturnType<typeof this.parse>)
|
react: ErrorBoundary.wrap(({ text, colorType, color }: ParsedColorInfo) => {
|
||||||
react({ text, colorType, color }: ParsedColorInfo) {
|
|
||||||
if (settings.store.renderType === RenderType.FOREGROUND) {
|
if (settings.store.renderType === RenderType.FOREGROUND) {
|
||||||
return <span style={{ color: color }}>{text}</span>;
|
return <span style={{ color: color }}>{text}</span>;
|
||||||
}
|
}
|
||||||
const styles = {
|
const styles = {
|
||||||
"--color": color,
|
"--color": color
|
||||||
} as React.CSSProperties;
|
} as React.CSSProperties;
|
||||||
|
|
||||||
if (settings.store.renderType === RenderType.BACKGROUND) {
|
if (settings.store.renderType === RenderType.BACKGROUND) {
|
||||||
const isDark = isColorDark(color, colorType);
|
const isDark = isColorDark(color, colorType);
|
||||||
const className = `vc-color-bg ${!isDark ? "vc-color-bg-invert" : ""}`;
|
const className = `vc-color-bg ${!isDark ? "vc-color-bg-invert" : ""}`;
|
||||||
return (
|
return <span className={className} style={styles}>{text}</span>;
|
||||||
<span className={className} style={styles}>
|
|
||||||
{text}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
// 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}
|
{text}
|
||||||
<span className="vc-color-block" style={styles}></span>
|
<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
|
// 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;
|
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||||
};
|
};
|
||||||
const isColorDark = (color: string, type: ColorType): boolean => {
|
const isColorDark = (color: string, type: ColorType): boolean => {
|
||||||
|
const border = 115;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ColorType.RGBA:
|
case ColorType.RGBA:
|
||||||
case ColorType.RGB: {
|
case ColorType.RGB: {
|
||||||
const match = color.match(/\d+/g)!;
|
const match = color.match(/\d+/g)!;
|
||||||
const lightness = calcRGBLightness(+match[0], +match[1], +match[2]);
|
const lightness = calcRGBLightness(+match[0], +match[1], +match[2]);
|
||||||
return lightness < 140;
|
return lightness < border;
|
||||||
}
|
}
|
||||||
case ColorType.HEX: {
|
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 r = (rgb >> 16) & 0xff;
|
||||||
const g = (rgb >> 8) & 0xff;
|
const g = (rgb >> 8) & 0xff;
|
||||||
const b = (rgb >> 0) & 0xff;
|
const b = (rgb >> 0) & 0xff;
|
||||||
|
|
||||||
const lightness = calcRGBLightness(r, g, b);
|
const lightness = calcRGBLightness(r, g, b);
|
||||||
return lightness < 140;
|
return lightness < border;
|
||||||
}
|
}
|
||||||
case ColorType.HSL: {
|
case ColorType.HSL: {
|
||||||
const match = color.match(/\d+/g)!;
|
const match = color.match(/\d+/g)!;
|
||||||
const lightness = +match[2];
|
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 {
|
function parseColor(str: string, type: ColorType): string {
|
||||||
str = str
|
str = str.toLowerCase().trim().replaceAll(/(\s|,)+/g, " ");
|
||||||
.toLowerCase()
|
|
||||||
.trim()
|
|
||||||
.replaceAll(/(\s|,)+/g, " ");
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ColorType.RGB:
|
case ColorType.RGB:
|
||||||
return str;
|
return str;
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
background: var(--color);
|
background: var(--color);
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
margin-bottom: 0.2rem;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
margin-left: 2px;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-color-bg {
|
.vc-color-bg {
|
||||||
|
@ -16,5 +17,5 @@
|
||||||
/* Light color in dark theme */
|
/* Light color in dark theme */
|
||||||
.theme-dark .vc-color-bg.vc-color-bg-invert,
|
.theme-dark .vc-color-bg.vc-color-bg-invert,
|
||||||
.theme-light .vc-color-bg:not(.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 { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { addMessagePreSendListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
import { addMessagePreSendListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
||||||
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
||||||
import { EquicordDevs } from "@utils/constants";
|
import { Devs, EquicordDevs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { Menu, React } from "@webpack/common";
|
import { Menu, React } from "@webpack/common";
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ migratePluginSettings("Signature", "SentVia");
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "Signature",
|
name: "Signature",
|
||||||
description: "Automated fingerprint/end text",
|
description: "Automated fingerprint/end text",
|
||||||
authors: [EquicordDevs.KrystalSkull],
|
authors: [Devs.Ven, Devs.Rini, Devs.ImBanana, EquicordDevs.KrystalSkull],
|
||||||
dependencies: ["MessageEventsAPI", "ChatInputButtonAPI"],
|
dependencies: ["MessageEventsAPI", "ChatInputButtonAPI"],
|
||||||
|
|
||||||
start: () => {
|
start: () => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue