diff --git a/saas-app/public/app-support.php b/saas-app/public/app-support.php index f374443..66dfaf6 100644 --- a/saas-app/public/app-support.php +++ b/saas-app/public/app-support.php @@ -2297,9 +2297,76 @@ function app_tenant_settings_defaults(): array 'location_label' => '', 'allow_self_service_booking' => '1', 'payment_hint' => 'Bitte Einzahlungen zeitnah verbuchen.', + 'brand_color' => '#005e3f', + 'brand_strong_color' => '#00452f', + 'accent_color' => '#c18a00', + 'background_color' => '#f4efe4', + 'card_color' => '#fffdf8', ]; } +function app_is_valid_hex_color(string $value): bool +{ + return preg_match('/^#[0-9A-Fa-f]{6}$/', $value) === 1; +} + +/** + * @return array{brand_color:string,brand_strong_color:string,accent_color:string,background_color:string,card_color:string,text_color:string,muted_color:string,brand_rgb:string,accent_rgb:string} + */ +function app_tenant_theme(array $settings): array +{ + $defaults = [ + 'brand_color' => '#005e3f', + 'brand_strong_color' => '#00452f', + 'accent_color' => '#c18a00', + 'background_color' => '#f4efe4', + 'card_color' => '#fffdf8', + 'text_color' => '#25180f', + 'muted_color' => '#63584a', + ]; + + foreach ($defaults as $key => $default) { + $candidate = strtoupper(trim((string) ($settings[$key] ?? $default))); + $defaults[$key] = app_is_valid_hex_color($candidate) ? $candidate : $default; + } + + $brandRgb = sscanf($defaults['brand_color'], '#%02x%02x%02x') ?: [0, 94, 63]; + $accentRgb = sscanf($defaults['accent_color'], '#%02x%02x%02x') ?: [193, 138, 0]; + + return [ + 'brand_color' => $defaults['brand_color'], + 'brand_strong_color' => $defaults['brand_strong_color'], + 'accent_color' => $defaults['accent_color'], + 'background_color' => $defaults['background_color'], + 'card_color' => $defaults['card_color'], + 'text_color' => $defaults['text_color'], + 'muted_color' => $defaults['muted_color'], + 'brand_rgb' => implode(', ', array_map('intval', $brandRgb)), + 'accent_rgb' => implode(', ', array_map('intval', $accentRgb)), + ]; +} + +function app_tenant_theme_root_css(array $settings): string +{ + $theme = app_tenant_theme($settings); + + return implode('', [ + '--bg:', $theme['background_color'], ';', + '--card:', $theme['card_color'], ';', + '--bg-elevated:', $theme['card_color'], ';', + '--bg-soft:', $theme['card_color'], ';', + '--text:', $theme['text_color'], ';', + '--ink:', $theme['text_color'], ';', + '--muted:', $theme['muted_color'], ';', + '--brand:', $theme['brand_color'], ';', + '--brand-2:', $theme['brand_strong_color'], ';', + '--brand-strong:', $theme['brand_strong_color'], ';', + '--accent:', $theme['accent_color'], ';', + '--brand-rgb:', $theme['brand_rgb'], ';', + '--accent-rgb:', $theme['accent_rgb'], ';', + ]); +} + function app_tenant_settings(PDO $pdo, string $tenantId): array { $settings = app_tenant_settings_defaults(); @@ -2331,6 +2398,11 @@ function app_save_tenant_settings(PDO $pdo, string $tenantId, array $data): void 'location_label' => trim((string) ($data['location_label'] ?? '')), 'allow_self_service_booking' => !empty($data['allow_self_service_booking']) ? '1' : '0', 'payment_hint' => trim((string) ($data['payment_hint'] ?? '')), + 'brand_color' => strtoupper(trim((string) ($data['brand_color'] ?? '#005e3f'))), + 'brand_strong_color' => strtoupper(trim((string) ($data['brand_strong_color'] ?? '#00452f'))), + 'accent_color' => strtoupper(trim((string) ($data['accent_color'] ?? '#c18a00'))), + 'background_color' => strtoupper(trim((string) ($data['background_color'] ?? '#f4efe4'))), + 'card_color' => strtoupper(trim((string) ($data['card_color'] ?? '#fffdf8'))), ]; if (!is_numeric($values['default_unit_price']) || (float) $values['default_unit_price'] <= 0) { @@ -2345,6 +2417,12 @@ function app_save_tenant_settings(PDO $pdo, string $tenantId, array $data): void throw new RuntimeException('Bitte gib eine gültige Support-E-Mail-Adresse an.'); } + foreach (['brand_color', 'brand_strong_color', 'accent_color', 'background_color', 'card_color'] as $colorKey) { + if (!app_is_valid_hex_color($values[$colorKey])) { + throw new RuntimeException('Bitte gib für die Farbfelder gültige HEX-Werte an.'); + } + } + $now = date('Y-m-d H:i:s'); foreach ($values as $key => $value) { diff --git a/saas-app/public/index.php b/saas-app/public/index.php index ddcb7f8..d1f2e9e 100644 --- a/saas-app/public/index.php +++ b/saas-app/public/index.php @@ -223,6 +223,7 @@ if ($auth !== null && isset($restrictedPages[$page]) && !$restrictedPages[$page] $canManageTenant = app_can_manage_tenant($auth); $tenantNavItems = app_tenant_navigation_items($auth, $tenantLicense); +$themeCss = app_tenant_theme_root_css($tenantSettings); ?> @@ -231,8 +232,8 @@ $tenantNavItems = app_tenant_navigation_items($auth, $tenantLicense); Kaffeeliste SaaS @@ -640,6 +641,11 @@ $tenantNavItems = app_tenant_navigation_items($auth, $tenantLicense); + + + + +