diff --git a/app/Livewire/Project/Edit.php b/app/Livewire/Project/Edit.php index a2d73eb5f..eafc649cb 100644 --- a/app/Livewire/Project/Edit.php +++ b/app/Livewire/Project/Edit.php @@ -14,17 +14,25 @@ class Edit extends Component public ?string $description = null; + public ?string $color = null; + protected function rules(): array { return [ 'name' => ValidationPatterns::nameRules(), 'description' => ValidationPatterns::descriptionRules(), + 'color' => ['nullable', 'string', 'regex:/^#[0-9A-Fa-f]{6}$/'], ]; } protected function messages(): array { - return ValidationPatterns::combinedMessages(); + return array_merge( + ValidationPatterns::combinedMessages(), + [ + 'color.regex' => 'The color must be a valid hex color code (e.g., #FF5733).', + ] + ); } public function mount(string $project_uuid) @@ -44,10 +52,12 @@ class Edit extends Component $this->project->update([ 'name' => $this->name, 'description' => $this->description, + 'color' => $this->color, ]); } else { $this->name = $this->project->name; $this->description = $this->project->description; + $this->color = $this->project->color; } } diff --git a/database/migrations/2026_02_03_001245_add_color_to_projects_table.php b/database/migrations/2026_02_03_001245_add_color_to_projects_table.php new file mode 100644 index 000000000..6ab3c480b --- /dev/null +++ b/database/migrations/2026_02_03_001245_add_color_to_projects_table.php @@ -0,0 +1,32 @@ +string('color', 7)->nullable()->after('description'); + }); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + if (Schema::hasColumn('projects', 'color')) { + Schema::table('projects', function (Blueprint $table) { + $table->dropColumn('color'); + }); + } + } +}; diff --git a/resources/js/app.js b/resources/js/app.js index 4dcae5f8e..2a3e8f3f2 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1,4 +1,8 @@ import { initializeTerminalComponent } from './terminal.js'; +import { initializeColorUtils } from './color-utils.js'; + +// Initialize color utilities globally +initializeColorUtils(); ['livewire:navigated', 'alpine:init'].forEach((event) => { document.addEventListener(event, () => { diff --git a/resources/js/color-utils.js b/resources/js/color-utils.js new file mode 100644 index 000000000..ef792502d --- /dev/null +++ b/resources/js/color-utils.js @@ -0,0 +1,30 @@ +/** + * Color utility functions for the application + */ +export function initializeColorUtils() { + /** + * Determines the appropriate text color (black or white) based on background color luminance + * Uses WCAG relative luminance formula for accessibility + * + * @param {string} bgColor - Hex color code (e.g., '#FF5733') + * @returns {string} Tailwind CSS class: 'text-black' or 'text-white' + */ + function getContrastTextColor(bgColor) { + if (!bgColor) return ''; + + // Convert hex to RGB + const hex = bgColor.replace('#', ''); + const r = parseInt(hex.substr(0, 2), 16); + const g = parseInt(hex.substr(2, 2), 16); + const b = parseInt(hex.substr(4, 2), 16); + + // Calculate relative luminance using WCAG formula + const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255; + + // Return dark text for light backgrounds, light text for dark backgrounds + return luminance > 0.5 ? 'text-black' : 'text-white'; + } + + // Make it globally available + window.getContrastTextColor = getContrastTextColor; +} diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php index 908c4a98a..15bb03591 100644 --- a/resources/views/livewire/dashboard.blade.php +++ b/resources/views/livewire/dashboard.blade.php @@ -29,7 +29,10 @@ @if ($projects->count() > 0)