mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-02-23 15:05:11 +00:00
more things
This commit is contained in:
parent
fc30e05414
commit
7f7456f347
2 changed files with 144 additions and 14 deletions
|
@ -37,7 +37,21 @@ interface OKLAB {
|
||||||
}
|
}
|
||||||
|
|
||||||
const RGB_REGEX = /rgb\((?:(\d+(?:\.\d+)?),? ?)(?:(\d+(?:\.\d+)?),? ?)(?:(\d+(?:\.\d+)?),? ?)\)/;
|
const RGB_REGEX = /rgb\((?:(\d+(?:\.\d+)?),? ?)(?:(\d+(?:\.\d+)?),? ?)(?:(\d+(?:\.\d+)?),? ?)\)/;
|
||||||
|
/**
|
||||||
|
* 1: colorspace
|
||||||
|
*
|
||||||
|
* 2: color 1 val
|
||||||
|
*
|
||||||
|
* 3?: color 1 percentage
|
||||||
|
*
|
||||||
|
* 4: color 2
|
||||||
|
*
|
||||||
|
* 5?: color 2 percentage
|
||||||
|
*/
|
||||||
|
const COLOR_MIX_REGEX = /color-mix\( ?in ([^,]+), ?([^,]+?) ?(\d+)?%? ?, (.+?) ?(\d+)?%? ?\)$/;
|
||||||
|
const color_mix_cleanup = (str: string) => str.replaceAll(/ +/g, " ").replaceAll("\n", "").replaceAll(/calc\(1 ?\* ? ([^)]+) \)/g, "$1");
|
||||||
|
const HSL_REGEX = /hsl\((\d+(?:\.\d+)?)(?<hueunits>turn|deg)?(?:, ?|,? )(\d+(?:\.\d+)?)%?(?:, ?|,? )(\d+(?:\.\d+)?)%?(?: ?\)$| ?\/ ?(\d?(?:\.\d+)?)\)$)/;
|
||||||
|
const hsl_cleanup = (str: string) => str.replaceAll(/calc\(1 ?\* ?([^)]+?)\)/g, "$1");
|
||||||
export class Color {
|
export class Color {
|
||||||
private sRGB: sRGB;
|
private sRGB: sRGB;
|
||||||
private get lRGB(): lRGB {
|
private get lRGB(): lRGB {
|
||||||
|
@ -135,12 +149,40 @@ export class Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static parse(color: string): Color {
|
/**
|
||||||
{
|
*
|
||||||
|
* @param withBG **If color has transparnecy, this needs to be provided**
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public static parse(color: string, withBG: string = ""): Color {
|
||||||
|
/* hex: */{
|
||||||
const c = color.replaceAll("#", "");
|
const c = color.replaceAll("#", "");
|
||||||
if (c.length === 3 || c.length === 6)
|
if (c.length === 3 || c.length === 6)
|
||||||
return new Color(Color.hexToRGB(color));
|
return new Color(Color.hexToRGB(color));
|
||||||
}
|
}
|
||||||
|
hsl: {
|
||||||
|
if (!color.startsWith("hsl(")) break hsl;
|
||||||
|
color = hsl_cleanup(color);
|
||||||
|
const parsed = color.match(HSL_REGEX);
|
||||||
|
if (!parsed) throw new Error("failed to parse HSL(): " + color);
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
let [, hue, units, sat, lig, alpha]: any = parsed;
|
||||||
|
hue = parseFloat(hue);
|
||||||
|
hue = units === "turn" ? hue * 360 : hue;
|
||||||
|
sat = parseFloat(sat);
|
||||||
|
lig = parseFloat(lig);
|
||||||
|
sat /= 100;
|
||||||
|
lig /= 100;
|
||||||
|
if (Number.isNaN(hue + sat + lig))
|
||||||
|
throw new Error("invalid hsl value. got: " + color);
|
||||||
|
const toRet = new Color({
|
||||||
|
type: "hsl",
|
||||||
|
h: hue,
|
||||||
|
s: sat,
|
||||||
|
l: lig,
|
||||||
|
});
|
||||||
|
return alpha ? toRet.withOpacity(Color.parse(withBG), alpha) : toRet;
|
||||||
|
}
|
||||||
rgb: {
|
rgb: {
|
||||||
const c = color.match(RGB_REGEX);
|
const c = color.match(RGB_REGEX);
|
||||||
if (!c) break rgb;
|
if (!c) break rgb;
|
||||||
|
@ -156,6 +198,44 @@ export class Color {
|
||||||
b: b / 255
|
b: b / 255
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
colormix: {
|
||||||
|
if (!color.startsWith("color-mix(")) break colormix;
|
||||||
|
color = color_mix_cleanup(color);
|
||||||
|
const parsed = color.match(COLOR_MIX_REGEX);
|
||||||
|
if (!parsed?.[3]) throw new Error("Error parsing color-mix: " + color);
|
||||||
|
const color1 = parsed[2],
|
||||||
|
colorSpace = parsed[1];
|
||||||
|
let color2: string, p1: string | undefined, p2: string | undefined;
|
||||||
|
switch (parsed.length) {
|
||||||
|
case 4: {
|
||||||
|
const [, , , c2] = parsed;
|
||||||
|
color2 = c2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 5: {
|
||||||
|
const [, , , c1P, c2] = parsed;
|
||||||
|
color2 = c2;
|
||||||
|
p1 = c1P;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
const [, , , c1P, c2, c2P] = parsed;
|
||||||
|
color2 = c2;
|
||||||
|
p1 = c1P;
|
||||||
|
p2 = c2P;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error("Error parsing color-mix" + color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p1 && p2 && +p1 + +p2 !== 100) {
|
||||||
|
throw new Error("percents do not add up to 100. percents that add up to less than 100 are not supported at this time");
|
||||||
|
}
|
||||||
|
const parsedColor1 = Color.parse(color1, withBG);
|
||||||
|
const parsedColor2 = Color.parse(color2, withBG);
|
||||||
|
return parsedColor1.mix(colorSpace, parseFloat(p1 || "50") / 100, parsedColor2);
|
||||||
|
}
|
||||||
throw new Error("Color not recognized. got: " + color);
|
throw new Error("Color not recognized. got: " + color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +243,7 @@ export class Color {
|
||||||
return (fg.lumin + 0.05) / (bg.lumin + 0.05);
|
return (fg.lumin + 0.05) / (bg.lumin + 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
public mix(colorspace: "oklab", thisPercent: number, other: Color, otherPercent = 1 - thisPercent): Color {
|
public mix(colorspace: "oklab" | (string & {}), thisPercent: number, other: Color, otherPercent = 1 - thisPercent): Color {
|
||||||
switch (colorspace) {
|
switch (colorspace) {
|
||||||
case "oklab": {
|
case "oklab": {
|
||||||
const okl1 = this.OKLAB;
|
const okl1 = this.OKLAB;
|
||||||
|
@ -193,6 +273,17 @@ export class Color {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private withOpacity(bg: Color, alpha: number): Color {
|
||||||
|
const r = (this.sRGB.r * alpha) + (bg.sRGB.r * (1 - alpha));
|
||||||
|
const g = (this.sRGB.g * alpha) + (bg.sRGB.g * (1 - alpha));
|
||||||
|
const b = (this.sRGB.b * alpha) + (bg.sRGB.b * (1 - alpha));
|
||||||
|
return new Color({
|
||||||
|
type: "srgb",
|
||||||
|
r,
|
||||||
|
g,
|
||||||
|
b
|
||||||
|
});
|
||||||
|
}
|
||||||
private static OKLABtolRGB({ l, a, b }: OKLAB): lRGB {
|
private static OKLABtolRGB({ l, a, b }: OKLAB): lRGB {
|
||||||
const l1 = Math.pow(l + 0.3963377774 * a + 0.2158037573 * b, 3);
|
const l1 = Math.pow(l + 0.3963377774 * a + 0.2158037573 * b, 3);
|
||||||
const m1 = Math.pow(l - 0.1055613458 * a - 0.0638541728 * b, 3);
|
const m1 = Math.pow(l - 0.1055613458 * a - 0.0638541728 * b, 3);
|
||||||
|
@ -291,3 +382,6 @@ export class Contrast {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getBackgroundColor = (c: CSSStyleDeclaration) => {
|
||||||
|
return c.getPropertyValue("--bg-overlay-chat") || c.getPropertyValue("--background-primary") || (() => { throw new Error("no background color found"); })();
|
||||||
|
};
|
||||||
|
|
|
@ -24,9 +24,10 @@ import { Logger } from "@utils/Logger";
|
||||||
import { useForceUpdater } from "@utils/react";
|
import { useForceUpdater } from "@utils/react";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByCodeLazy } from "@webpack";
|
import { findByCodeLazy } from "@webpack";
|
||||||
import { ChannelStore, GuildMemberStore, GuildStore, useEffect, useMemo, useState } from "@webpack/common";
|
import { ChannelStore, GuildMemberStore, GuildStore, useEffect, useMemo, useRef, useState } from "@webpack/common";
|
||||||
|
import Message from "discord-types/general/Message";
|
||||||
|
|
||||||
import { Color, Contrast } from "./color";
|
import { Color, Contrast, getBackgroundColor } from "./color";
|
||||||
|
|
||||||
|
|
||||||
const useMessageAuthor = findByCodeLazy('"Result cannot be null because the message is not null"');
|
const useMessageAuthor = findByCodeLazy('"Result cannot be null because the message is not null"');
|
||||||
|
@ -193,7 +194,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
predicate: () => settings.store.colorChatMessages
|
predicate: () => settings.store.colorChatMessages
|
||||||
},
|
},
|
||||||
// HORROR
|
// HORROR: ref for message content to get background colors
|
||||||
{
|
{
|
||||||
find: "#{intl::MESSAGE_EDITED}",
|
find: "#{intl::MESSAGE_EDITED}",
|
||||||
replacement: {
|
replacement: {
|
||||||
|
@ -207,9 +208,45 @@ export default definePlugin({
|
||||||
match: /(?<=ref:)\i/,
|
match: /(?<=ref:)\i/,
|
||||||
replace: "vc_ref"
|
replace: "vc_ref"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// cap contrast of usernames
|
||||||
|
{
|
||||||
|
find: "style:\"username\"",
|
||||||
|
replacement: {
|
||||||
|
match: /(?<=message:(\i).*)(?<=color:(\i).*)(?<=void 0,)/,
|
||||||
|
replace: "...$self.capContrast($2, $1),"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
capContrast(color: string, { mentioned }: Message) {
|
||||||
|
const ref = useRef<{ ref: Element; }>(null);
|
||||||
|
const contrast = useGetContrastValue();
|
||||||
|
const [dep, update] = useForceUpdater(true);
|
||||||
|
return useMemo(() => {
|
||||||
|
try {
|
||||||
|
if (color == null || contrast === 1) return {};
|
||||||
|
if (!ref.current?.ref) {
|
||||||
|
console.log("updating");
|
||||||
|
setTimeout(update, 0);
|
||||||
|
return { ref };
|
||||||
|
}
|
||||||
|
const computed = getComputedStyle(ref.current.ref);
|
||||||
|
const standardBG = getBackgroundColor(computed);
|
||||||
|
const bgColor = mentioned ? computed.getPropertyValue("--background-mentioned") : standardBG;
|
||||||
|
if (!bgColor) throw new Error("Background color not found");
|
||||||
|
return {
|
||||||
|
ref,
|
||||||
|
style: {
|
||||||
|
color: new Contrast(Color.parse(bgColor, standardBG)).calculateMinContrastColor(Color.parse(color), contrast)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}, [ref?.current?.ref, contrast, color, dep, mentioned]);
|
||||||
|
},
|
||||||
|
|
||||||
getColorString(userId: string, channelOrGuildId: string) {
|
getColorString(userId: string, channelOrGuildId: string) {
|
||||||
try {
|
try {
|
||||||
const guildId = ChannelStore.getChannel(channelOrGuildId)?.guild_id ?? GuildStore.getGuild(channelOrGuildId)?.id;
|
const guildId = ChannelStore.getChannel(channelOrGuildId)?.guild_id ?? GuildStore.getGuild(channelOrGuildId)?.id;
|
||||||
|
@ -254,17 +291,16 @@ export default definePlugin({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// why
|
// why
|
||||||
if (!ref.current) setTimeout(update, 0);
|
if (!ref.current) {
|
||||||
|
setTimeout(update, 0);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
const computed = window.getComputedStyle(ref.current);
|
const computed = window.getComputedStyle(ref.current);
|
||||||
const textNormal = computed.getPropertyValue("--text-normal"),
|
const textNormal = computed.getPropertyValue("--text-normal"),
|
||||||
headerPrimary = computed.getPropertyValue("--header-primary"),
|
headerPrimary = computed.getPropertyValue("--header-primary"),
|
||||||
textMuted = computed.getPropertyValue("--text-muted");
|
textMuted = computed.getPropertyValue("--text-muted");
|
||||||
const bgOverlayChat = computed.getPropertyValue("--bg-overlay-chat"),
|
|
||||||
backgroundPrimary = computed.getPropertyValue("--background-primary");
|
const bg = new Contrast(Color.parse(getBackgroundColor(computed)));
|
||||||
if (!(bgOverlayChat || backgroundPrimary)) {
|
|
||||||
throw new Error("No background color found");
|
|
||||||
}
|
|
||||||
const bg = new Contrast(Color.parse(bgOverlayChat || backgroundPrimary));
|
|
||||||
const rc = Color.parse(author.colorString);
|
const rc = Color.parse(author.colorString);
|
||||||
const mkColor = c => bg.calculateMinContrastColor(rc.mix("oklab", messageSaturation / 100, Color.parse(c)), contrast);
|
const mkColor = c => bg.calculateMinContrastColor(rc.mix("oklab", messageSaturation / 100, Color.parse(c)), contrast);
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Add table
Reference in a new issue