Add color utility functions and theme palette integration
- Introduced utility functions for color manipulation: `fhHexToRgb`, `fhRgbToHex`, `fhMixHex`, `fhRelativeLuminance`, and `fhContrastText`. - Implemented a comprehensive theme palette based on the user's favorite color, including primary, secondary, and semantic colors. - Updated CSS variables in the stylesheet to reflect the new theme structure, enhancing consistency across the UI. - Modified header to dynamically apply theme styles based on the generated palette, improving visual coherence.
This commit is contained in:
@@ -55,6 +55,61 @@ $isCalendarTvView = $activeTab === 'calendar' && isset($_GET['view']) && (string
|
||||
|
||||
$familyHubApiBase = familyHubWebApiBase();
|
||||
|
||||
if (!function_exists('fhHexToRgb')) {
|
||||
function fhHexToRgb(string $hex): array
|
||||
{
|
||||
if (!preg_match('/^#([0-9A-Fa-f]{6})$/', $hex, $m)) {
|
||||
return [74, 144, 226];
|
||||
}
|
||||
$raw = $m[1];
|
||||
return [
|
||||
hexdec(substr($raw, 0, 2)),
|
||||
hexdec(substr($raw, 2, 2)),
|
||||
hexdec(substr($raw, 4, 2)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('fhRgbToHex')) {
|
||||
function fhRgbToHex(array $rgb): string
|
||||
{
|
||||
$r = max(0, min(255, (int) round((float) ($rgb[0] ?? 0))));
|
||||
$g = max(0, min(255, (int) round((float) ($rgb[1] ?? 0))));
|
||||
$b = max(0, min(255, (int) round((float) ($rgb[2] ?? 0))));
|
||||
return sprintf('#%02x%02x%02x', $r, $g, $b);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('fhMixHex')) {
|
||||
function fhMixHex(string $leftHex, string $rightHex, float $rightWeight): string
|
||||
{
|
||||
$weight = max(0.0, min(1.0, $rightWeight));
|
||||
$left = fhHexToRgb($leftHex);
|
||||
$right = fhHexToRgb($rightHex);
|
||||
$mixed = [
|
||||
($left[0] * (1 - $weight)) + ($right[0] * $weight),
|
||||
($left[1] * (1 - $weight)) + ($right[1] * $weight),
|
||||
($left[2] * (1 - $weight)) + ($right[2] * $weight),
|
||||
];
|
||||
return fhRgbToHex($mixed);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('fhRelativeLuminance')) {
|
||||
function fhRelativeLuminance(string $hex): float
|
||||
{
|
||||
[$r, $g, $b] = fhHexToRgb($hex);
|
||||
return (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) / 255;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('fhContrastText')) {
|
||||
function fhContrastText(string $backgroundHex): string
|
||||
{
|
||||
return fhRelativeLuminance($backgroundHex) >= 0.6 ? '#111827' : '#ffffff';
|
||||
}
|
||||
}
|
||||
|
||||
$favoriteColor = '#4a90e2';
|
||||
if (
|
||||
$activePerson !== null
|
||||
@@ -63,16 +118,50 @@ if (
|
||||
) {
|
||||
$favoriteColor = (string) $activePerson['favoriteColor'];
|
||||
}
|
||||
|
||||
$themePalette = [];
|
||||
$themePalette['accent'] = $favoriteColor;
|
||||
$themePalette['primary'] = $favoriteColor;
|
||||
$themePalette['primary_hover'] = fhMixHex($favoriteColor, '#000000', 0.12);
|
||||
$themePalette['primary_active'] = fhMixHex($favoriteColor, '#000000', 0.2);
|
||||
$themePalette['primary_subtle'] = fhMixHex($favoriteColor, '#ffffff', 0.86);
|
||||
$themePalette['primary_border'] = fhMixHex($favoriteColor, '#ffffff', 0.64);
|
||||
$themePalette['primary_text'] = fhContrastText($themePalette['primary']);
|
||||
$themePalette['primary_subtle_text'] = fhContrastText($themePalette['primary_subtle']);
|
||||
$themePalette['secondary'] = fhMixHex($favoriteColor, '#ffffff', 0.76);
|
||||
$themePalette['secondary_hover'] = fhMixHex($favoriteColor, '#ffffff', 0.66);
|
||||
$themePalette['secondary_active'] = fhMixHex($favoriteColor, '#ffffff', 0.57);
|
||||
$themePalette['secondary_border'] = fhMixHex($favoriteColor, '#ffffff', 0.5);
|
||||
$themePalette['secondary_text'] = fhContrastText($themePalette['secondary']);
|
||||
$themePalette['tertiary'] = fhMixHex($favoriteColor, '#ffffff', 0.9);
|
||||
$themePalette['tertiary_hover'] = fhMixHex($favoriteColor, '#ffffff', 0.82);
|
||||
$themePalette['tertiary_active'] = fhMixHex($favoriteColor, '#ffffff', 0.73);
|
||||
$themePalette['tertiary_border'] = fhMixHex($favoriteColor, '#ffffff', 0.62);
|
||||
$themePalette['tertiary_text'] = fhContrastText($themePalette['tertiary']);
|
||||
$themePalette['focus_ring'] = fhMixHex($favoriteColor, '#ffffff', 0.35);
|
||||
$themePalette['surface_tint'] = fhMixHex($favoriteColor, '#ffffff', 0.93);
|
||||
$themePalette['header_gradient_end'] = fhMixHex($favoriteColor, '#0f172a', 0.58);
|
||||
|
||||
$semanticBase = [
|
||||
'success' => '#198754',
|
||||
'warning' => '#f59e0b',
|
||||
'danger' => '#dc3545',
|
||||
'info' => '#0ea5e9',
|
||||
];
|
||||
foreach ($semanticBase as $key => $baseHex) {
|
||||
$main = fhMixHex($baseHex, $favoriteColor, 0.2);
|
||||
$themePalette[$key] = $main;
|
||||
$themePalette[$key . '_hover'] = fhMixHex($main, '#000000', 0.1);
|
||||
$themePalette[$key . '_active'] = fhMixHex($main, '#000000', 0.18);
|
||||
$themePalette[$key . '_subtle'] = fhMixHex($main, '#ffffff', 0.84);
|
||||
$themePalette[$key . '_border'] = fhMixHex($main, '#ffffff', 0.62);
|
||||
$themePalette[$key . '_text'] = fhContrastText($main);
|
||||
$themePalette[$key . '_subtle_text'] = fhContrastText($themePalette[$key . '_subtle']);
|
||||
}
|
||||
|
||||
$headerThemeClass = 'header-tone-dark';
|
||||
if (preg_match('/^#([0-9A-Fa-f]{6})$/', $favoriteColor, $m)) {
|
||||
$hex = $m[1];
|
||||
$r = hexdec(substr($hex, 0, 2));
|
||||
$g = hexdec(substr($hex, 2, 2));
|
||||
$b = hexdec(substr($hex, 4, 2));
|
||||
$relativeLuminance = (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) / 255;
|
||||
if ($relativeLuminance >= 0.62) {
|
||||
$headerThemeClass = 'header-tone-light';
|
||||
}
|
||||
if (fhRelativeLuminance($themePalette['primary']) >= 0.62) {
|
||||
$headerThemeClass = 'header-tone-light';
|
||||
}
|
||||
|
||||
include 'includes/header.php';
|
||||
|
||||
Reference in New Issue
Block a user