2025-10-18 21:05:34 +03:00
|
|
|
|
import {readCssVar} from "../utils/css-var";
|
|
|
|
|
|
import Color, { ColorInstance } from "color";
|
|
|
|
|
|
|
2024-07-25 00:01:39 +03:00
|
|
|
|
const registeredClasses = new Set<string>();
|
2022-09-25 14:19:30 +02:00
|
|
|
|
|
2025-10-18 21:05:34 +03:00
|
|
|
|
// Read the color lightness limits defined in the theme as CSS variables
|
|
|
|
|
|
|
|
|
|
|
|
const lightThemeColorMaxLightness = readCssVar(
|
|
|
|
|
|
document.documentElement,
|
|
|
|
|
|
"tree-item-light-theme-max-color-lightness"
|
|
|
|
|
|
).asNumber(70);
|
|
|
|
|
|
|
|
|
|
|
|
const darkThemeColorMinLightness = readCssVar(
|
|
|
|
|
|
document.documentElement,
|
|
|
|
|
|
"tree-item-dark-theme-min-color-lightness"
|
|
|
|
|
|
).asNumber(50);
|
|
|
|
|
|
|
2024-07-25 20:36:15 +03:00
|
|
|
|
function createClassForColor(color: string | null) {
|
2022-09-25 14:19:30 +02:00
|
|
|
|
if (!color?.trim()) {
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const normalizedColorName = color.replace(/[^a-z0-9]/gi, "");
|
|
|
|
|
|
|
|
|
|
|
|
if (!normalizedColorName.trim()) {
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-21 15:19:05 +01:00
|
|
|
|
const className = `color-${normalizedColorName}`;
|
2022-09-25 14:19:30 +02:00
|
|
|
|
|
2025-10-18 21:05:34 +03:00
|
|
|
|
const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!, darkThemeColorMinLightness!);
|
|
|
|
|
|
if (!adjustedColor) return "";
|
|
|
|
|
|
|
2022-09-25 14:19:30 +02:00
|
|
|
|
if (!registeredClasses.has(className)) {
|
2025-10-18 21:05:34 +03:00
|
|
|
|
$("head").append(`<style>
|
|
|
|
|
|
.${className}, span.fancytree-active.${className} {
|
|
|
|
|
|
--light-theme-custom-color: ${adjustedColor.lightThemeColor};
|
|
|
|
|
|
--dark-theme-custom-color: ${adjustedColor.darkThemeColor}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>`);
|
2022-09-25 14:19:30 +02:00
|
|
|
|
|
|
|
|
|
|
registeredClasses.add(className);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return className;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-18 21:05:34 +03:00
|
|
|
|
/**
|
|
|
|
|
|
* Returns a pair of colors — one optimized for light themes and the other for dark themes, derived
|
|
|
|
|
|
* from the specified color to maintain sufficient contrast with each theme.
|
|
|
|
|
|
* The adjustment is performed by limiting the color’s lightness in the CIELAB color space,
|
|
|
|
|
|
* according to the lightThemeMaxLightness and darkThemeMinLightness parameters.
|
|
|
|
|
|
*/
|
|
|
|
|
|
function adjustColorLightness(color: string, lightThemeMaxLightness: number, darkThemeMinLightness: number) {
|
|
|
|
|
|
let labColor: ColorInstance | undefined = undefined;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// Parse the given color in the CIELAB color space
|
|
|
|
|
|
labColor = Color(color).lab();
|
|
|
|
|
|
} catch (ex) {
|
|
|
|
|
|
console.error(`Failed to parse color: "${color}"`, ex);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// For the light theme, limit the maximum lightness
|
|
|
|
|
|
const lightThemeColor = labColor.l(Math.min(labColor.l(), lightThemeMaxLightness)).hex();
|
|
|
|
|
|
// For the light theme, limit the minimum lightness
|
|
|
|
|
|
const darkThemeColor = labColor.l(Math.max(labColor.l(), darkThemeMinLightness)).hex();
|
|
|
|
|
|
|
|
|
|
|
|
return {lightThemeColor, darkThemeColor};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-25 14:19:30 +02:00
|
|
|
|
export default {
|
|
|
|
|
|
createClassForColor
|
2025-10-18 21:05:34 +03:00
|
|
|
|
};
|