This commit is contained in:
Dan Harrin
2021-02-14 00:51:50 +00:00
parent af61a3dfc4
commit 7675eac73d
10 changed files with 180 additions and 136 deletions
+7 -7
View File
@@ -1,8 +1,8 @@
<img {{ $attributes->merge([
'src' => $src(),
'srcset' => $srcSet(),
'alt' => $user->name,
'width' => $size,
'height' => $size,
'loading' => 'lazy'
]) }} />
'src' => $src(),
'srcset' => $srcSet(),
'alt' => $user->name,
'width' => $size,
'height' => $size,
'loading' => 'lazy'
]) }} />
-53
View File
@@ -1,53 +0,0 @@
@extends('filament::components.layouts.field-group')
@section('field')
<div x-cloak
x-data="{ isUploading: false, progress: 0 }"
x-on:livewire-upload-start="isUploading = true"
x-on:livewire-upload-finish="isUploading = false"
x-on:livewire-upload-error="isUploading = false"
x-on:livewire-upload-progress="progress = $event.detail.progress"
class="flex items-center space-x-4">
<div class="flex-shrink-0 relative">
<div class="rounded-full shadow-sm flex overflow-hidden">
@if ($field->avatar && ! $errors->has($field->name))
<img src="{{ $field->avatar->temporaryUrl() }}" alt="{{ $field->user->name }}"
class="h-full object-cover" width="{{ $field->size }}" height="{{ $field->size }}"
loading="lazy">
@else
<x-filament::modal close-button class="flex">
<x-filament-avatar :size="$field->size" :user="$field->user" />
<x-slot name="content">
<x-filament-avatar :size="320" :user="$field->user" />
</x-slot>
</x-filament::modal>
@endif
</div>
@if ($field->user->avatar)
<button type="button"
wire:click="deleteFile($field->name)"
class="absolute top-0 right-0 w-4 h-4 rounded-full bg-gray-800 text-white flex items-center justify-center hover:bg-red-700 transition-colors duration-200">
<span class="sr-only">{{ __('filament::avatar.delete') }}</span>
<x-heroicon-o-x class="w-3 h-3" />
</button>
@endif
</div>
<div class="flex-grow relative">
<label class="btn btn-sm" for="{{ $field->id }}">{{ __($field->buttonLabel) }}</label>
<input type="file"
{{ $field->nameAttribute }}="{{ $field->name }}"
class="sr-only"
id="{{ $field->id }}"
{{ Filament\format_attributes($field->extraAttributes) }}
/>
<div x-show="isUploading" :aria-hidden="!isUploading" class="absolute bottom-0 -mb-3 w-48 max-w-full">
<x-filament::progress progress="progress" />
</div>
</div>
</div>
@overwrite
+23 -5
View File
@@ -7,7 +7,11 @@
<script src="https://unpkg.com/filepond/dist/filepond.js"></script>
<script src="https://unpkg.com/filepond-plugin-file-validate-size/dist/filepond-plugin-file-validate-size.js"></script>
<script src="https://unpkg.com/filepond-plugin-file-validate-type/dist/filepond-plugin-file-validate-type.js"></script>
<script src="https://unpkg.com/filepond-plugin-image-crop/dist/filepond-plugin-image-crop.js"></script>
<script src="https://unpkg.com/filepond-plugin-image-exif-orientation/dist/filepond-plugin-image-exif-orientation.js"></script>
<script src="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.js"></script>
<script src="https://unpkg.com/filepond-plugin-image-resize/dist/filepond-plugin-image-resize.js"></script>
<script src="https://unpkg.com/filepond-plugin-image-transform/dist/filepond-plugin-image-transform.js"></script>
@endpushonce
<x-filament::field-group
@@ -23,19 +27,27 @@
x-init="
FilePond.registerPlugin(FilePondPluginFileValidateSize)
FilePond.registerPlugin(FilePondPluginFileValidateType)
FilePond.registerPlugin(FilePondPluginImageCrop)
FilePond.registerPlugin(FilePondPluginImageExifOrientation)
FilePond.registerPlugin(FilePondPluginImagePreview)
FilePond.registerPlugin(FilePondPluginImageResize)
FilePond.registerPlugin(FilePondPluginImageTransform)
let config = {
acceptedFileTypes: {{ json_encode($field->acceptedFileTypes) }},
files: [],
labelIdle: '{{ __($field->placeholder) }}',
{{ $field->maxSize ? "maxFileSize: '$field->maxSize KB'," : null }}
{{ $field->minSize ? "minFileSize: '$field->minSize KB'," : null }}
{{ $field->imageCropAspectRatio !== null ? "imageCropAspectRatio: '{$field->imageCropAspectRatio}'," : null }}
{{ $field->imagePreviewHeight !== null ? "imagePreviewHeight: {$field->imagePreviewHeight}," : null }}
{{ $field->imageResizeTargetHeight !== null ? "imageResizeTargetHeight: {$field->imageResizeTargetHeight}," : null }}
{{ $field->imageResizeTargetWidth !== null ? "imageResizeTargetWidth: {$field->imageResizeTargetWidth}," : null }}
{{ $field->placeholder !== null ? 'labelIdle: \''.__($field->placeholder).'\',' : null }}
{{ $field->maxSize !== null ? "maxFileSize: '{$field->maxSize} KB'," : null }}
{{ $field->minSize !== null ? "minFileSize: '{$field->minSize} KB'," : null }}
server: {
load: (source, load, error, progress, abort, headers) => {
fetch(source).then((response) => {
response.blob().then((myBlob) => {
load(myBlob)
response.blob().then((blob) => {
load(blob)
})
})
},
@@ -59,6 +71,12 @@
})
},
},
styleButtonProcessItemPosition: '{{ $field->uploadButtonPosition }}',
styleButtonRemoveItemPosition: '{{ $field->removeUploadButtonPosition }}',
styleLoadIndicatorPosition: '{{ $field->loadingIndicatorPosition }}',
{{ $field->panelAspectRatio !== null ? "stylePanelAspectRatio: '{$field->panelAspectRatio}'," : null }}
{{ $field->panelLayout !== null ? "stylePanelLayout: '{$field->panelLayout}'," : null }}
styleProgressIndicatorPosition: '{{ $field->uploadProgressIndicatorPosition }}',
}
$wire.getUploadedFileUrl('{{ $field->name }}', '{{ $field->disk }}').then((uploadedFileUrl) => {
+4 -40
View File
@@ -2,48 +2,12 @@
namespace Filament\Fields;
class Avatar extends InputField
class Avatar extends File
{
public $avatar;
public $buttonLabel = 'filament::avatar.change';
public $nameAttribute = 'wire:model';
public $size = 64;
public $user;
public static function make($name)
public function __construct($name)
{
return static::make($name)->image();
}
parent::__construct($name);
public function avatar($avatar)
{
$this->avatar = $avatar;
return $this;
}
public function buttonLabel(string $label)
{
$this->buttonLabel = $label;
return $this;
}
public function size($size)
{
$this->size = $size;
return $this;
}
public function user($user)
{
$this->user = $user;
return $this;
$this->image();
}
}
+107
View File
@@ -16,10 +16,30 @@ class File extends InputField
public $disk;
public $imageCropAspectRatio;
public $imagePreviewHeight;
public $imageResizeTargetHeight;
public $imageResizeTargetWidth;
public $loadingIndicatorPosition = 'right';
public $maxSize;
public $minSize;
public $panelAspectRatio = null;
public $panelLayout = null;
public $removeUploadButtonPosition = 'left';
public $uploadButtonPosition = 'right';
public $uploadProgressIndicatorPosition = 'right';
public $visibility = 'public';
public function __construct($name)
@@ -43,6 +63,23 @@ class File extends InputField
return $this;
}
public function avatar()
{
$this->extraAttributes(['class' => 'w-36']);
$this->image();
$this->imageCropAspectRatio('1:1');
$this->imagePreviewHeight(170);
$this->imageResizeTargetHeight(500);
$this->imageResizeTargetWidth(500);
$this->loadingIndicatorPosition('center bottom');
$this->panelLayout('compact circle');
$this->removeUploadButtonPosition('center bottom');
$this->uploadButtonPosition('center bottom');
$this->uploadProgressIndicatorPosition('center bottom');
return $this;
}
public function disk($disk)
{
$this->disk = $disk;
@@ -83,6 +120,41 @@ class File extends InputField
return $this;
}
public function imageCropAspectRatio($ratio)
{
$this->imageCropAspectRatio = $ratio;
return $this;
}
public function imagePreviewHeight($height)
{
$this->imagePreviewHeight = $height;
return $this;
}
public function imageResizeTargetHeight($height)
{
$this->imageResizeTargetHeight = $height;
return $this;
}
public function imageResizeTargetWidth($width)
{
$this->imageResizeTargetWidth = $width;
return $this;
}
public function loadingIndicatorPosition($position)
{
$this->loadingIndicatorPosition = $position;
return $this;
}
public function maxSize($size)
{
$this->maxSize = $size;
@@ -101,6 +173,41 @@ class File extends InputField
return $this;
}
public function panelAspectRatio($ratio)
{
$this->panelAspectRatio = $ratio;
return $this;
}
public function panelLayout($layout)
{
$this->panelLayout = $layout;
return $this;
}
public function removeUploadButtonPosition($position)
{
$this->removeUploadButtonPosition = $position;
return $this;
}
public function uploadButtonPosition($position)
{
$this->uploadButtonPosition = $position;
return $this;
}
public function uploadProgressIndicatorPosition($position)
{
$this->uploadProgressIndicatorPosition = $position;
return $this;
}
public function visibility($visibility)
{
$this->visibility = $visibility;
-2
View File
@@ -6,9 +6,7 @@ use Filament\Fields\File;
use Filament\Fields\InputField;
use Filament\Fields\Tab;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Livewire\WithFileUploads;
+1 -1
View File
@@ -20,7 +20,7 @@ class ImageController extends Controller
'cache' => Storage::disk(config('filament.cache_disk'))->getDriver(),
'cache_path_prefix' => config('filament.cache_path_prefix'),
'response' => new LaravelResponseFactory(app('request')),
'source' => Storage::disk(config('filament.storage_disk'))->getDriver(),
'source' => Storage::disk(config('filament.default_filesystem_disk'))->getDriver(),
]);
return $server->getImageResponse($path, request()->all());
+7 -2
View File
@@ -33,11 +33,9 @@ class EditAccount extends Component
return [
Fields\Fieldset::make()->fields([
Fields\Text::make('record.name')
->label('Name')
->disableAutocomplete()
->required(),
Fields\Text::make('record.email')
->label('Email')
->email()
->disableAutocomplete()
->required()
@@ -58,6 +56,9 @@ class EditAccount extends Component
->requiredWith('newPassword'),
])
->columns(2),
Fields\File::make('record.avatar')
->avatar()
->directory('filament-avatars'),
];
}
@@ -68,6 +69,10 @@ class EditAccount extends Component
public function submit()
{
$this->validateTemporaryUploadedFiles();
$this->storeTemporaryUploadedFiles();
$this->validate();
if ($this->newPassword) {
+19 -19
View File
@@ -16,33 +16,33 @@ class Avatar extends Component
public function __construct($user, $size = 48, $dprs = [1, 2, 3])
{
$this->user = $user;
$this->size = $size;
$this->dprs = $dprs;
$this->size = $size;
$this->user = $user;
}
public function srcSet()
{
$srcSet = [];
foreach ($this->dprs as $dpr) {
$srcSet[] = $this->src($dpr) . ' ' . $dpr . 'x';
}
return implode(', ', $srcSet);
}
public function src(int $dpr = 1)
public function src($dpr = 1)
{
if (! $this->user->avatar) {
return Gravatar::src($this->user->email, $this->size * $dpr);
}
return get_image_url($this->user->avatar, [
'w' => $this->size,
'h' => $this->size,
'fit' => 'crop',
'dpr' => $dpr,
]);
return get_image_url(
$this->user->avatar,
[
'dpr' => $dpr,
'fit' => 'crop',
'h' => $this->size,
'w' => $this->size,
]
);
}
public function srcSet()
{
return collect($this->dprs)
->map(fn ($dpr) => $this->src($dpr) . ' ' . $dpr . 'x')
->implode(', ');
}
public function render()
+12 -7
View File
@@ -16,18 +16,23 @@ class Image extends Component
public function __construct($src, $manipulations, $dprs = [1, 1.5, 2, 3])
{
$this->dprs = $dprs;
$this->src = $src;
$this->manipulations = $manipulations;
}
public function srcSet()
{
return collect($this->dprs)->map(fn ($dpr) => $this->src($dpr) . ' ' . $dpr . 'x')->implode(', ');
$this->src = $src;
}
public function src($dpr = 1)
{
return get_image_url($this->src, array_merge(['dpr' => $dpr], $this->manipulations));
return get_image_url(
$this->src,
array_merge(['dpr' => $dpr], $this->manipulations),
);
}
public function srcSet()
{
return collect($this->dprs)
->map(fn ($dpr) => $this->src($dpr) . ' ' . $dpr . 'x')
->implode(', ');
}
public function render()