Chinh sua giao dien phu hop tailwind css va upload
Some checks failed
Tests / PHP 8.3 (push) Has been cancelled
Tests / PHP 8.4 (push) Has been cancelled
Tests / PHP 8.5 (push) Has been cancelled

This commit is contained in:
2026-05-05 09:25:28 +00:00
parent 8c6b71cb8a
commit fb1f82e1a0
12 changed files with 834 additions and 466 deletions

View File

@@ -424,3 +424,78 @@ $user->assignRole('manager');
13. **i18n - ChartWidget heading**: `$heading`/`$description` are raw properties — must override `getHeading()`/`getDescription()`.
14. **i18n - form labels**: Form fields without `->label()` use Filament's `filament-panels::` namespace — always add explicit `->label(__('key'))`.
15. **i18n - Filament vendor**: Filament ships 57 Vietnamese translation files — auto-activated when `APP_LOCALE=vi`.
16. **FileUpload disk**: Always use `disk('public')` for all FileUpload components. NEVER use `disk('local')` — causes file not found errors.
17. **FileUpload dehydrated**: Do NOT use `dehydrated(false)` — prevents file paths from being available in afterSave()/afterCreate(). Use property to store paths in mutateFormDataBeforeSave().
18. **File metadata safety**: Always check `$disk->exists($path)` before calling `$disk->mimeType()` or `$disk->size()` — prevents UnableToRetrieveMetadata error.
19. **FileUpload in Actions**: When handling file uploads in Action callbacks (e.g., transfer attachments), file paths are strings (not UploadedFile). Create records directly instead of using FileService::upload().
20. **Tailwind CSS in Filament**: Custom blade views render inside Filament layout which does NOT include full Tailwind CSS build. Must add needed utilities to `public/css/filament-custom.css` with `!important`.
21. **SVG icon sizing**: Use inline `width`/`height` attributes on SVG icons (e.g., `<svg width="14" height="14">`) instead of Tailwind classes (`w-3.5 h-3.5`) — prevents Filament CSS from overriding sizes.
## File Upload Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ FileUpload Component (disk='public') │
│ → Filament uploads via AJAX to storage/app/public/ │
│ → File path stored in Livewire state │
│ │
│ Form Submit │
│ → mutateFormDataBeforeSave() stores paths in property │
│ → Removes 'attachments' from $data before saving model │
│ │
│ afterSave()/afterCreate() │
│ → Uses stored paths to create FeedbackAttachment records │
│ → Checks $disk->exists($path) before getting metadata │
│ → Uses asset('storage/' . $path) for URLs │
└─────────────────────────────────────────────────────────────────┘
```
### FileUpload Pattern (correct):
```php
// In Form
FileUpload::make('attachments')
->disk('public') // ALWAYS public
->directory('feedback-attachments')
// Do NOT use ->dehydrated(false)
// In Page class
protected array $pendingAttachments = [];
protected function mutateFormDataBeforeSave(array $data): array
{
$this->pendingAttachments = $data['attachments'] ?? [];
unset($data['attachments']); // Remove before saving model
return $data;
}
protected function afterSave(): void
{
$disk = Storage::disk('public');
foreach ($this->pendingAttachments as $path) {
if (! $disk->exists($path)) continue; // Safety check
$this->getRecord()->attachments()->create([
'path' => $path,
'disk' => 'public',
'mime_type' => $disk->mimeType($path),
'size' => $disk->size($path),
// ...
]);
}
}
```
### Tailwind CSS in Filament (correct):
```php
// Filament uses its own CSS build, NOT the project's Tailwind build
// Custom blade views need utilities added to public/css/filament-custom.css
// In filament-custom.css:
.flex { display: flex !important; }
.items-center { align-items: center !important; }
.gap-2 { gap: 0.5rem !important; }
// ... add all needed utilities with !important
// For SVG icons, use inline attributes:
<svg width="14" height="14" class="text-blue-600">...</svg>
// NOT: <svg class="w-3.5 h-3.5 text-blue-600">...</svg>