Skip to content
This repository was archived by the owner on Nov 22, 2025. It is now read-only.

Commit d85fed0

Browse files
authored
feat: tag colours (#85)
* wip * fixed formatting
1 parent a8cf827 commit d85fed0

File tree

16 files changed

+146
-17
lines changed

16 files changed

+146
-17
lines changed

app/Http/Controllers/Api/TagController.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use App\Http\Resources\TagResource;
99
use App\Models\Tag;
1010
use App\Models\User;
11+
use App\Rules\ValidHexColour;
1112
use Illuminate\Http\JsonResponse;
1213
use Illuminate\Http\Request;
1314
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
@@ -157,6 +158,7 @@ private function validateTag(Request $request, bool $isUpdate = false): array
157158
$rules = [
158159
'label' => ['required', 'string', 'max:255'],
159160
'description' => ['nullable', 'string', 'max:1000'],
161+
'colour' => ['nullable', 'string', new ValidHexColour],
160162
];
161163

162164
if ($isUpdate) {

app/Http/Resources/TagResource.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function toArray(Request $request): array
2323
'user_id' => $this->resource->user_id,
2424
'label' => $this->resource->label,
2525
'description' => $this->resource->description,
26+
'colour' => $this->resource->colour,
2627
'created_at' => $this->resource->created_at,
2728
'updated_at' => $this->resource->updated_at,
2829
];

app/Livewire/Tags/CreateForm.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace App\Livewire\Tags;
66

77
use App\Models\Tag;
8+
use App\Rules\ValidHexColour;
89
use Illuminate\Http\RedirectResponse;
910
use Illuminate\Support\Facades\Auth;
1011
use Illuminate\Support\Facades\Redirect;
@@ -26,6 +27,9 @@ class CreateForm extends Component
2627
/** @var string|null The optional description for the new tag. */
2728
public ?string $description = null;
2829

30+
/** @var string|null The optional colour identifier for the tag. */
31+
public ?string $colour = null;
32+
2933
/**
3034
* Handle the form submission for creating a new tag.
3135
*
@@ -36,6 +40,7 @@ public function submit(): RedirectResponse|Redirector
3640
$this->validate([
3741
'label' => ['required', 'string'],
3842
'description' => ['nullable', 'string'],
43+
'colour' => ['nullable', 'string', new ValidHexColour],
3944
], [
4045
'label.required' => __('Please enter a label.'),
4146
]);
@@ -44,6 +49,7 @@ public function submit(): RedirectResponse|Redirector
4449
'user_id' => Auth::id(),
4550
'label' => $this->label,
4651
'description' => $this->description ?? null,
52+
'colour' => $this->colour,
4753
]);
4854

4955
Toaster::success('The tag :label has been added.', ['label' => $tag->label]);

app/Livewire/Tags/UpdateForm.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace App\Livewire\Tags;
66

77
use App\Models\Tag;
8+
use App\Rules\ValidHexColour;
89
use Illuminate\Http\RedirectResponse;
910
use Illuminate\Support\Facades\Redirect;
1011
use Illuminate\View\View;
@@ -25,6 +26,9 @@ class UpdateForm extends Component
2526
/** @var string|null The updated description for the tag. */
2627
public ?string $description = null;
2728

29+
/** @var string|null An optional updated colour identifier. */
30+
public ?string $colour = null;
31+
2832
/** @var Tag The tag instance being updated. */
2933
public Tag $tag;
3034

@@ -38,6 +42,7 @@ public function mount(Tag $tag): void
3842
$this->tag = $tag;
3943
$this->label = $tag->getAttribute('label');
4044
$this->description = $tag->getAttribute('description') ?? null;
45+
$this->colour = $tag->getAttribute('colour');
4146
}
4247

4348
/**
@@ -52,13 +57,15 @@ public function submit(): RedirectResponse|Redirector
5257
$this->validate([
5358
'label' => ['required', 'string'],
5459
'description' => ['nullable', 'string'],
60+
'colour' => ['nullable', 'string', new ValidHexColour],
5561
], [
5662
'label.required' => __('Please enter a label.'),
5763
]);
5864

5965
$this->tag->update([
6066
'label' => $this->label,
6167
'description' => $this->description ?? null,
68+
'colour' => $this->colour ?? null,
6269
]);
6370

6471
$this->tag->save();

app/Rules/ValidHexColour.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Rules;
6+
7+
use Closure;
8+
use Illuminate\Contracts\Validation\ValidationRule;
9+
use Override;
10+
11+
class ValidHexColour implements ValidationRule
12+
{
13+
/**
14+
* Determine if the validation rule passes.
15+
*/
16+
#[Override]
17+
public function validate(string $attribute, mixed $value, Closure $fail): void
18+
{
19+
if (! is_string($value)) {
20+
$fail('The :attribute must be a string.');
21+
22+
return;
23+
}
24+
25+
$value = trim($value);
26+
27+
$pattern = '/^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/';
28+
29+
if (! preg_match($pattern, $value)) {
30+
$fail('The :attribute must be a valid hex color code (e.g., #d37445 or #f60).');
31+
}
32+
}
33+
}

database/factories/TagFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public function definition(): array
1212
return [
1313
'label' => fake()->unique()->word(),
1414
'description' => fake()->sentence(),
15+
'colour' => fake()->hexColor(),
1516
'user_id' => User::factory()->create()->id,
1617
];
1718
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
public function up(): void
10+
{
11+
Schema::table('tags', function (Blueprint $table) {
12+
$table->string('colour')->nullable();
13+
});
14+
}
15+
};

resources/views/livewire/backup-tasks/forms/create-backup-task-form.blade.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,16 @@ class="mt-1 block w-full"
132132
<div class="mt-4">
133133
<x-input-label for="tags" :value="__('Tags')" />
134134
@foreach ($availableTags as $tag)
135-
<x-checkbox
136-
id="tag-{{ $tag->id }}"
137-
wire:model="selectedTags"
138-
value="{{ $tag->id }}"
139-
name="tags[]"
140-
label="{{ $tag->label }}"
141-
></x-checkbox>
135+
<div class="flex items-center">
136+
<div class="h-4 w-4 rounded mr-2 shrink-0" style="background-color: {{ $tag->colour }};"></div>
137+
<x-checkbox
138+
id="tag-{{ $tag->id }}"
139+
wire:model="selectedTags"
140+
value="{{ $tag->id }}"
141+
name="tags[]"
142+
label="{{ $tag->label }}"
143+
></x-checkbox>
144+
</div>
142145
@endforeach
143146

144147
<x-input-error :messages="$errors->get('selectedTags')" class="mt-2" />

resources/views/livewire/backup-tasks/forms/update-backup-task-form.blade.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -292,13 +292,19 @@ class="text-sm text-gray-600 underline ease-in-out hover:text-gray-900 dark:text
292292
<div class="mt-4">
293293
<x-input-label for="tags" :value="__('Tags')" />
294294
@foreach ($availableTags as $tag)
295-
<x-checkbox
296-
id="tag-{{ $tag->id }}"
297-
wire:model="selectedTags"
298-
value="{{ $tag->id }}"
299-
name="tags[]"
300-
label="{{ $tag->label }}"
301-
></x-checkbox>
295+
<div class="flex items-center">
296+
<div
297+
class="mr-2 h-4 w-4 shrink-0 rounded"
298+
style="background-color: {{ $tag->colour }}"
299+
></div>
300+
<x-checkbox
301+
id="tag-{{ $tag->id }}"
302+
wire:model="selectedTags"
303+
value="{{ $tag->id }}"
304+
name="tags[]"
305+
label="{{ $tag->label }}"
306+
></x-checkbox>
307+
</div>
302308
@endforeach
303309

304310
<x-input-error :messages="$errors->get('selectedTags')" class="mt-2" />

resources/views/livewire/backup-tasks/tables/index-item.blade.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,10 @@ class="inline-flex items-center rounded-md bg-white px-2.5 py-0.5 text-xs font-m
464464
<div class="max-h-96 space-y-4 overflow-y-auto">
465465
@forelse ($backupTask->tags as $tag)
466466
<div class="flex items-center justify-between rounded-lg bg-gray-100 p-3 dark:bg-gray-700">
467-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ $tag->label }}</span>
467+
<div class="flex items-center">
468+
<div class="h-4 w-4 rounded mr-2 shrink-0" style="background-color: {{ $tag->colour }};"></div>
469+
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ $tag->label }}</span>
470+
</div>
468471
</div>
469472
@empty
470473
<div class="py-8 text-center text-gray-500 dark:text-gray-400">

0 commit comments

Comments
 (0)