BLOG-165 Adjust label text color based on background luminance for better contrast (#298)
All checks were successful
Frontend CI / build (push) Successful in 1m39s

### Description

This PR introduces support for dark background colors on post labels.

Specifically, the following changes have been made:
1. **Luminance & Color Contrast**: Added `isDark` and `contrastingTextColor` getters in `ColorViewModel`. The color contrast detection has been improved to use the standard sRGB relative luminance formula (per WCAG 2.x standard) with a threshold of `0.179` to determine if a background is dark, ensuring much more accurate contrast adjustments than a simple YIQ calculation.
2. **Text Color Adjustment**: Sets the text color of the `PostLabel` dynamically to `#ffffff` if the background is dark, and inherits the default color if the background is light.
3. **Indicator Dot Styling**: Adjusts the background color of the small decorative dot inside `PostLabel` using a lighter variant (`lighten(0.4)`) on dark labels, and a darker variant (`darken(0.2)`) on light labels to ensure visual clarity.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #165

### Checklist

- [x] A milestone is set
- [x] The related issues has been linked to this branch

Reviewed-on: #298
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
This commit was merged in pull request #298.
This commit is contained in:
2026-05-23 00:31:57 +08:00
committed by Gitea Server
parent 745a1de78a
commit 39e712036e
2 changed files with 25 additions and 2 deletions

View File

@@ -83,6 +83,24 @@ export class ColorViewModel {
return hexString.slice(0, 7);
}
get isDark(): boolean {
const normalize = (val: number) => {
const c = val / 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
};
const r = normalize(this.red);
const g = normalize(this.green);
const b = normalize(this.blue);
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
return luminance < 0.179;
}
get contrastingTextColor(): string {
return this.isDark ? '#ffffff' : 'inherit';
}
private toHsl(): Hsl {
const r = this.red / 255;
const g = this.green / 255;

View File

@@ -6,8 +6,13 @@
<div
class="flex h-fit w-fit flex-row flex-nowrap items-center gap-x-1 rounded-full px-2 py-0.5"
style="background-color: {label.color.hex};"
style="background-color: {label.color.hex}; color: {label.color.contrastingTextColor};"
>
<div class="size-2 rounded-full" style="background-color: {label.color.darken(0.2).hex};"></div>
<div
class="size-2 rounded-full"
style="background-color: {label.color.isDark
? label.color.lighten(0.4).hex
: label.color.darken(0.2).hex};"
></div>
<span class="text-xs text-nowrap">{label.name}</span>
</div>