From e8bb6848bbcc00a9f45aeadd27f633a9d816173f Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 8 Aug 2025 18:55:17 +0200 Subject: [PATCH 1/4] Allow to show video / audio preview on upload --- demo/app/Sharp/Posts/PostForm.php | 6 +- demo/app/Sharp/Posts/PostShow.php | 2 +- .../form/components/fields/upload/Upload.vue | 123 ++++++++++-------- resources/js/show/components/fields/File.vue | 88 +++++++------ resources/js/types/generated.d.ts | 2 + .../Form/Fields/FormUploadFieldValueData.php | 1 + src/Data/Show/Fields/ShowFileFieldData.php | 1 + .../Eloquent/Uploads/SharpUploadModel.php | 15 +++ ...arpUploadModelFormAttributeTransformer.php | 36 ++++- 9 files changed, 175 insertions(+), 99 deletions(-) diff --git a/demo/app/Sharp/Posts/PostForm.php b/demo/app/Sharp/Posts/PostForm.php index bd0c6538f..7ea8fd4d9 100644 --- a/demo/app/Sharp/Posts/PostForm.php +++ b/demo/app/Sharp/Posts/PostForm.php @@ -126,8 +126,8 @@ public function buildFormFields(FieldsContainer $formFields): void ) ->addItemField( SharpFormUploadField::make('document') - ->setMaxFileSize(1) - ->setAllowedExtensions(['pdf', 'zip']) + ->setMaxFileSize(2) + ->setAllowedExtensions(['pdf', 'zip', 'mp4', 'mp3']) ->setStorageDisk('local') ->setStorageBasePath('data/posts/{id}') ->addConditionalDisplay('!is_link'), @@ -203,7 +203,7 @@ public function find($id): array return $this ->setCustomTransformer('author_id', fn ($value, Post $instance) => $instance->author) ->setCustomTransformer('cover', new SharpUploadModelFormAttributeTransformer()) - ->setCustomTransformer('attachments[document]', new SharpUploadModelFormAttributeTransformer()) + ->setCustomTransformer('attachments[document]', new SharpUploadModelFormAttributeTransformer(withPlayablePreview: true)) ->transform(Post::with('cover', 'attachments', 'categories')->findOrFail($id)); } diff --git a/demo/app/Sharp/Posts/PostShow.php b/demo/app/Sharp/Posts/PostShow.php index 25a4fa9fa..a2bcbc759 100644 --- a/demo/app/Sharp/Posts/PostShow.php +++ b/demo/app/Sharp/Posts/PostShow.php @@ -154,7 +154,7 @@ public function find(mixed $id): array ->setCustomTransformer('cover', new SharpUploadModelThumbnailUrlTransformer(500)) ->setCustomTransformer( 'attachments[document]', - new SharpUploadModelFormAttributeTransformer(withThumbnails: true) + new SharpUploadModelFormAttributeTransformer(withPlayablePreview: true) ) ->setCustomTransformer('attachments[link_url]', fn ($value, $instance) => $instance->is_link ? sprintf('%s', $value, str($value)->limit(30)) diff --git a/resources/js/form/components/fields/upload/Upload.vue b/resources/js/form/components/fields/upload/Upload.vue index 4840066ab..54be7fdc4 100644 --- a/resources/js/form/components/fields/upload/Upload.vue +++ b/resources/js/form/components/fields/upload/Upload.vue @@ -68,6 +68,7 @@ }>(); const form = useParentForm(); const transformedImg = ref(); + const playablePreviewUrl = ref(); const uppyFile = ref>(); const isEditable = computed(() => { return props.value && canTransform(props.value.name, props.value.mime_type) && !props.hasError @@ -135,6 +136,8 @@ const blob = await response.blob(); transformedImg.value = URL.createObjectURL(blob); } + } else if(file.type?.startsWith('video/') || file.type?.startsWith('audio/')) { + playablePreviewUrl.value = URL.createObjectURL(file.data); } }) .on('restriction-failed', (file, error) => { @@ -350,6 +353,7 @@ uppy.removeFile(uppyFile.value.id); uppyFile.value = null; transformedImg.value = null; + playablePreviewUrl.value = null; editModalImageUrl.value = null; } } @@ -382,6 +386,9 @@ if(!props.persistThumbnailUrl && transformedImg.value) { URL.revokeObjectURL(transformedImg.value); } + if(playablePreviewUrl.value) { + URL.revokeObjectURL(playablePreviewUrl.value); + } emit('uploading', false); }); @@ -392,69 +399,83 @@