mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
wip
This commit is contained in:
@@ -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'
|
||||
]) }} />
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user