$styleCfg->stylePalettes ?? [], 'menuPalettes' => $styleCfg->menuPalettes ?? [], ]; } return [ 'stylePalettes' => $styleCfg['stylePalettes'] ?? [], 'menuPalettes' => $styleCfg['menuPalettes'] ?? [], ]; } /** * GET /api/v1/ui/style * Get current UI style preferences */ public function getStyle() { $user = $this->getCurrentUser(); if (!$user) { return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED); } try { $session = session(); $cfg = $this->styleConfig(); return $this->success([ 'style_color' => $session->get('style_color'), 'menu_color' => $session->get('menu_color'), 'menu_custom_bg' => $session->get('menu_custom_bg'), 'menu_custom_text' => $session->get('menu_custom_text'), 'menu_custom_mode' => $session->get('menu_custom_mode'), 'available_palettes' => $cfg['stylePalettes'] ?? [], 'available_menus' => $cfg['menuPalettes'] ?? [], ], 'UI style preferences retrieved successfully'); } catch (\Throwable $e) { log_message('error', 'UI style error: ' . $e->getMessage()); return $this->respondError('Failed to retrieve UI style', Response::HTTP_INTERNAL_SERVER_ERROR); } } /** * POST /api/v1/ui/style * Update UI style preferences via POST body */ public function updateStyle() { $user = $this->getCurrentUser(); if (!$user) { return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED); } $data = $this->payloadData(); if (empty($data)) { return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST); } return $this->processStyleUpdate($data); } /** * GET /api/v1/ui/style (with query parameters) * Update UI style preferences via GET parameters (for backward compatibility) */ public function style() { $user = $this->getCurrentUser(); if (!$user) { return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED); } // Get parameters from query string $accent = (string) $this->request->getGet('accent'); $menu = (string) $this->request->getGet('menu'); $menuBg = (string) $this->request->getGet('menu_bg'); $menuTx = (string) $this->request->getGet('menu_text'); $menuMd = (string) $this->request->getGet('menu_mode'); $data = []; if ($accent !== '') { $data['accent'] = $accent; } if ($menu !== '') { $data['menu'] = $menu; } if ($menuBg !== '') { $data['menu_bg'] = $menuBg; } if ($menuTx !== '') { $data['menu_text'] = $menuTx; } if ($menuMd !== '') { $data['menu_mode'] = $menuMd; } if (empty($data)) { // No parameters provided, return current style return $this->getStyle(); } return $this->processStyleUpdate($data); } /** * Process style update from either GET or POST */ private function processStyleUpdate(array $data): JsonResponse { try { $session = session(); $cfg = $this->styleConfig(); if (isset($data['accent']) && $data['accent'] !== '' && isset(($cfg['stylePalettes'] ?? [])[$data['accent']])) { $session->put('style_color', $data['accent']); } if (isset($data['menu']) && $data['menu'] !== '') { if (isset(($cfg['menuPalettes'] ?? [])[$data['menu']])) { $session->put('menu_color', $data['menu']); } elseif (strtolower($data['menu']) === 'custom' || (isset($data['menu_bg']) && $data['menu_bg'] !== '') || (isset($data['menu_text']) && $data['menu_text'] !== '')) { // Allow custom menu colors $bg = $this->normalizeHex($data['menu_bg'] ?? ''); $tx = $this->normalizeHex($data['menu_text'] ?? ''); if ($bg === '' && $tx === '') { // no valid values; ignore } else { if ($bg === '') { $bg = '#0f172a'; } if ($tx === '') { $tx = '#ffffff'; } // Determine mode if requested auto or missing $mode = isset($data['menu_mode']) && in_array($data['menu_mode'], ['light', 'dark'], true) ? $data['menu_mode'] : $this->autoModeForBg($bg); $session->put('menu_color', 'custom'); $session->put('menu_custom_bg', $bg); $session->put('menu_custom_text', $tx); $session->put('menu_custom_mode', $mode); } } } return $this->success([ 'style_color' => $session->get('style_color'), 'menu_color' => $session->get('menu_color'), 'menu_custom_bg' => $session->get('menu_custom_bg'), 'menu_custom_text' => $session->get('menu_custom_text'), 'menu_custom_mode' => $session->get('menu_custom_mode'), ], 'UI style updated successfully'); } catch (\Throwable $e) { log_message('error', 'UI style update error: ' . $e->getMessage()); return $this->respondError('Failed to update UI style', Response::HTTP_INTERNAL_SERVER_ERROR); } } private function normalizeHex(string $hex): string { $h = trim($hex); if ($h === '') { return ''; } if ($h[0] !== '#') { $h = '#' . $h; } if (preg_match('/^#([0-9a-fA-F]{3})$/', $h, $m)) { $r = $m[1][0]; $g = $m[1][1]; $b = $m[1][2]; return '#' . $r . $r . $g . $g . $b . $b; } if (preg_match('/^#([0-9a-fA-F]{6})$/', $h)) { return strtoupper($h); } return ''; } private function autoModeForBg(string $hexBg): string { $hex = ltrim($hexBg, '#'); if (strlen($hex) !== 6) { return 'dark'; } $r = hexdec(substr($hex, 0, 2)); $g = hexdec(substr($hex, 2, 2)); $b = hexdec(substr($hex, 4, 2)); $lum = (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) / 255; return $lum < 0.5 ? 'dark' : 'light'; } }