feat(style): Mejorar derivePanelPalette con HSL

- Header usa darkenHsl/lightenHsl (preserva tono mejor que RGB)
- Selección sin foco usa desaturate + lightenHsl (más elegante)
- Nueva función contrastTextColor() para texto automático b/n
- Test adicional para contrastTextColor

Z-Design ahora produce paletas más armónicas desde color base.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
R.Eugenio 2025-12-29 15:36:20 +01:00
parent c330492022
commit b5a4205c29

View file

@ -1048,12 +1048,13 @@ fn deriveDarkPalette(base: Color) PanelColorScheme {
.etiquetas = white.darken(30), // ~70% brightness .etiquetas = white.darken(30), // ~70% brightness
.placeholder = gray, .placeholder = gray,
// Header: darkened base color // Header: darkened using HSL (preserves hue better than RGB darken)
.header = base.darken(60), .header = base.darkenHsl(50),
// Selection: where the base color SHINES // Selection: base color at full strength when focused
.seleccion_fondo_con_focus = base, // Full color! .seleccion_fondo_con_focus = base,
.seleccion_fondo_sin_focus = base.blendTowards(gray, 50), // Muted // Unfocused: desaturated and slightly lightened (HSL-based, more elegant)
.seleccion_fondo_sin_focus = base.desaturate(60).lightenHsl(10),
// Borders: accent on focus, subtle otherwise // Borders: accent on focus, subtle otherwise
.borde_con_focus = base, .borde_con_focus = base,
@ -1079,12 +1080,13 @@ fn deriveLightPalette(base: Color) PanelColorScheme {
.etiquetas = black.lighten(40), // ~60% darkness .etiquetas = black.lighten(40), // ~60% darkness
.placeholder = gray, .placeholder = gray,
// Header: very light version of base // Header: lightened using HSL (preserves hue better)
.header = base.blendTowards(white, 85), .header = base.lightenHsl(40),
// Selection: base color (slightly lightened for readability) // Selection: base color at full strength when focused
.seleccion_fondo_con_focus = base, .seleccion_fondo_con_focus = base,
.seleccion_fondo_sin_focus = base.blendTowards(white, 60), // Unfocused: desaturated and lightened (HSL-based)
.seleccion_fondo_sin_focus = base.desaturate(50).lightenHsl(30),
// Borders: accent on focus, subtle otherwise // Borders: accent on focus, subtle otherwise
.borde_con_focus = base, .borde_con_focus = base,
@ -1092,6 +1094,17 @@ fn deriveLightPalette(base: Color) PanelColorScheme {
}; };
} }
/// Get appropriate text color (black or white) based on background luminosity.
/// Uses the HSL lightness value to determine contrast.
pub fn contrastTextColor(background: Color) Color {
const hsl = background.toHsl();
// If background is light (L > 0.5), use dark text; otherwise use light text
return if (hsl.l > 0.5)
Color.rgb(20, 20, 25) // Dark text for light backgrounds
else
Color.rgb(245, 245, 245); // Light text for dark backgrounds
}
// ============================================================================= // =============================================================================
// Z-Design Tests // Z-Design Tests
// ============================================================================= // =============================================================================
@ -1149,3 +1162,20 @@ test "derivePanelPalette light mode" {
try std.testing.expect(palette.fondo_con_focus.g > 245); try std.testing.expect(palette.fondo_con_focus.g > 245);
try std.testing.expect(palette.fondo_con_focus.b > 250); try std.testing.expect(palette.fondo_con_focus.b > 250);
} }
test "contrastTextColor" {
// Dark background should get light text
const dark_bg = Color.rgb(30, 30, 30);
const text_on_dark = contrastTextColor(dark_bg);
try std.testing.expect(text_on_dark.r > 200); // Light text
// Light background should get dark text
const light_bg = Color.rgb(240, 240, 240);
const text_on_light = contrastTextColor(light_bg);
try std.testing.expect(text_on_light.r < 50); // Dark text
// Mid-gray (128/255 = 0.502 > 0.5) gets dark text
const mid_gray = Color.rgb(128, 128, 128);
const text_on_mid = contrastTextColor(mid_gray);
try std.testing.expect(text_on_mid.r < 50); // Dark text (L = 0.502 > 0.5)
}