From 20c0c6dee99e518ce6c9a0809704da8fab09f7dd Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Wed, 11 Mar 2026 07:43:31 +0700 Subject: [PATCH] feat: Integrate Filament upload and PDF viewer packages, add media library configuration, and implement responsive image handling in views. --- composer.json | 2 + composer.lock | 119 ++++++- config/media-library.php | 303 ++++++++++++++++++ .../asmit/filament-upload/filepond-pdf.css | 56 ++++ .../components/filepond-pdf.js | 1 + .../vendor/media-library/image.blade.php | 1 + .../media-library/placeholderSvg.blade.php | 6 + .../media-library/responsiveImage.blade.php | 1 + .../responsiveImageWithPlaceholder.blade.php | 1 + 9 files changed, 489 insertions(+), 1 deletion(-) create mode 100644 config/media-library.php create mode 100644 public/css/asmit/filament-upload/filepond-pdf.css create mode 100644 public/js/asmit/filament-upload/components/filepond-pdf.js create mode 100644 resources/views/vendor/media-library/image.blade.php create mode 100644 resources/views/vendor/media-library/placeholderSvg.blade.php create mode 100644 resources/views/vendor/media-library/responsiveImage.blade.php create mode 100644 resources/views/vendor/media-library/responsiveImageWithPlaceholder.blade.php diff --git a/composer.json b/composer.json index 09d2bb2..6f44805 100644 --- a/composer.json +++ b/composer.json @@ -7,9 +7,11 @@ "license": "MIT", "require": { "php": "^8.2", + "asmit/filament-upload": "^2.0", "diogogpinto/filament-auth-ui-enhancer": "^2.0", "filament/filament": "^5.0", "filament/spatie-laravel-media-library-plugin": "^5.0", + "joaopaulolndev/filament-pdf-viewer": "^3.0", "laravel/framework": "^12.0", "laravel/tinker": "^2.10.1", "saade/filament-facehash": "^1.0" diff --git a/composer.lock b/composer.lock index 7a891bc..dcc7d35 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fe430b74f6d03416758a4b8daeda7417", + "content-hash": "a83572109ce443bd242db06e43da23d5", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -72,6 +72,53 @@ }, "time": "2025-12-04T13:38:21+00:00" }, + { + "name": "asmit/filament-upload", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/AsmitNepali/filament-upload.git", + "reference": "eb7ad5a394820a999dcb2b53fdf9176776e7843c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/AsmitNepali/filament-upload/zipball/eb7ad5a394820a999dcb2b53fdf9176776e7843c", + "reference": "eb7ad5a394820a999dcb2b53fdf9176776e7843c", + "shasum": "" + }, + "require": { + "filament/support": "^3.0|^4.0|^5.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Asmit\\FilamentUpload\\FilamentUploadServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Asmit\\FilamentUpload\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "AsmitNepali", + "email": "mail2asmitnepali@gmail.com" + } + ], + "description": "Filament PDF file upload and preview.", + "support": { + "issues": "https://github.com/AsmitNepali/filament-upload/issues", + "source": "https://github.com/AsmitNepali/filament-upload/tree/v2.0.0" + }, + "time": "2026-01-17T06:36:31+00:00" + }, { "name": "blade-ui-kit/blade-heroicons", "version": "2.6.0", @@ -2207,6 +2254,76 @@ ], "time": "2025-08-22T14:27:06+00:00" }, + { + "name": "joaopaulolndev/filament-pdf-viewer", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/joaopaulolndev/filament-pdf-viewer.git", + "reference": "a4d208db6018184cb19eb9b2f19029fb42ba6bd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/joaopaulolndev/filament-pdf-viewer/zipball/a4d208db6018184cb19eb9b2f19029fb42ba6bd2", + "reference": "a4d208db6018184cb19eb9b2f19029fb42ba6bd2", + "shasum": "" + }, + "require": { + "filament/filament": "^5.3", + "php": "^8.2", + "spatie/laravel-package-tools": "^1.15.0" + }, + "require-dev": { + "laravel/pint": "^1.0", + "nunomaduro/collision": "^7.9|^8.6", + "orchestra/testbench": "^8.0|^9.0|^10.0", + "pestphp/pest": "^2.1|^3.4.7", + "pestphp/pest-plugin-arch": "^2.0|^3.0", + "pestphp/pest-plugin-laravel": "^2.0|^3.1.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Joaopaulolndev\\FilamentPdfViewer\\FilamentPdfViewerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Joaopaulolndev\\FilamentPdfViewer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "João Paulo Leite Nascimento", + "email": "joaopauloln7@gmail.com", + "role": "Developer" + } + ], + "description": "Filament package to show pdf document viewer", + "homepage": "https://github.com/joaopaulolndev/filament-pdf-viewer", + "keywords": [ + "filament-pdf-viewer", + "joaopaulolndev", + "laravel" + ], + "support": { + "issues": "https://github.com/joaopaulolndev/filament-pdf-viewer/issues", + "source": "https://github.com/joaopaulolndev/filament-pdf-viewer" + }, + "funding": [ + { + "url": "https://github.com/joaopaulolndev", + "type": "github" + } + ], + "time": "2026-03-04T02:40:18+00:00" + }, { "name": "kirschbaum-development/eloquent-power-joins", "version": "4.2.11", diff --git a/config/media-library.php b/config/media-library.php new file mode 100644 index 0000000..8b4d6c0 --- /dev/null +++ b/config/media-library.php @@ -0,0 +1,303 @@ + env('MEDIA_DISK', 'public'), + + /* + * The maximum file size of an item in bytes. + * Adding a larger file will result in an exception. + */ + 'max_file_size' => 1024 * 1024 * 10, // 10MB + + /* + * This queue connection will be used to generate derived and responsive images. + * Leave empty to use the default queue connection. + */ + 'queue_connection_name' => env('QUEUE_CONNECTION', 'sync'), + + /* + * This queue will be used to generate derived and responsive images. + * Leave empty to use the default queue. + */ + 'queue_name' => env('MEDIA_QUEUE', ''), + + /* + * By default all conversions will be performed on a queue. + */ + 'queue_conversions_by_default' => env('QUEUE_CONVERSIONS_BY_DEFAULT', true), + + /* + * Should database transactions be run after database commits? + */ + 'queue_conversions_after_database_commit' => env('QUEUE_CONVERSIONS_AFTER_DB_COMMIT', true), + + /* + * The fully qualified class name of the media model. + */ + 'media_model' => Spatie\MediaLibrary\MediaCollections\Models\Media::class, + + /* + * The fully qualified class name of the media observer. + */ + 'media_observer' => Spatie\MediaLibrary\MediaCollections\Models\Observers\MediaObserver::class, + + /* + * When enabled, media collections will be serialised using the default + * laravel model serialization behaviour. + * + * Keep this option disabled if using Media Library Pro components (https://medialibrary.pro) + */ + 'use_default_collection_serialization' => false, + + /* + * The fully qualified class name of the model used for temporary uploads. + * + * This model is only used in Media Library Pro (https://medialibrary.pro) + */ + 'temporary_upload_model' => Spatie\MediaLibraryPro\Models\TemporaryUpload::class, + + /* + * When enabled, Media Library Pro will only process temporary uploads that were uploaded + * in the same session. You can opt to disable this for stateless usage of + * the pro components. + */ + 'enable_temporary_uploads_session_affinity' => true, + + /* + * When enabled, Media Library pro will generate thumbnails for uploaded file. + */ + 'generate_thumbnails_for_temporary_uploads' => true, + + /* + * This is the class that is responsible for naming generated files. + */ + 'file_namer' => Spatie\MediaLibrary\Support\FileNamer\DefaultFileNamer::class, + + /* + * The class that contains the strategy for determining a media file's path. + */ + 'path_generator' => App\MediaLibrary\CustomPathGenerator::class, + + /* + * The class that contains the strategy for determining how to remove files. + */ + 'file_remover_class' => Spatie\MediaLibrary\Support\FileRemover\DefaultFileRemover::class, + + /* + * Here you can specify which path generator should be used for the given class. + */ + 'custom_path_generators' => [ + // Model::class => PathGenerator::class + // or + // 'model_morph_alias' => PathGenerator::class + ], + + /* + * When urls to files get generated, this class will be called. Use the default + * if your files are stored locally above the site root or on s3. + */ + 'url_generator' => Spatie\MediaLibrary\Support\UrlGenerator\DefaultUrlGenerator::class, + + /* + * Moves media on updating to keep path consistent. Enable it only with a custom + * PathGenerator that uses, for example, the media UUID. + */ + 'moves_media_on_update' => false, + + /* + * Whether to activate versioning when urls to files get generated. + * When activated, this attaches a ?v=xx query string to the URL. + */ + 'version_urls' => false, + + /* + * The media library will try to optimize all converted images by removing + * metadata and applying a little bit of compression. These are + * the optimizers that will be used by default. + */ + 'image_optimizers' => [ + Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [ + '-m85', // set maximum quality to 85% + '--force', // ensure that progressive generation is always done also if a little bigger + '--strip-all', // this strips out all text information such as comments and EXIF data + '--all-progressive', // this will make sure the resulting image is a progressive one + ], + Spatie\ImageOptimizer\Optimizers\Pngquant::class => [ + '--force', // required parameter for this package + ], + Spatie\ImageOptimizer\Optimizers\Optipng::class => [ + '-i0', // this will result in a non-interlaced, progressive scanned image + '-o2', // this set the optimization level to two (multiple IDAT compression trials) + '-quiet', // required parameter for this package + ], + Spatie\ImageOptimizer\Optimizers\Svgo::class => [ + '--disable=cleanupIDs', // disabling because it is known to cause troubles + ], + Spatie\ImageOptimizer\Optimizers\Gifsicle::class => [ + '-b', // required parameter for this package + '-O3', // this produces the slowest but best results + ], + Spatie\ImageOptimizer\Optimizers\Cwebp::class => [ + '-m 6', // for the slowest compression method in order to get the best compression. + '-pass 10', // for maximizing the amount of analysis pass. + '-mt', // multithreading for some speed improvements. + '-q 90', // quality factor that brings the least noticeable changes. + ], + Spatie\ImageOptimizer\Optimizers\Avifenc::class => [ + '-a cq-level=23', // constant quality level, lower values mean better quality and greater file size (0-63). + '-j all', // number of jobs (worker threads, "all" uses all available cores). + '--min 0', // min quantizer for color (0-63). + '--max 63', // max quantizer for color (0-63). + '--minalpha 0', // min quantizer for alpha (0-63). + '--maxalpha 63', // max quantizer for alpha (0-63). + '-a end-usage=q', // rate control mode set to Constant Quality mode. + '-a tune=ssim', // SSIM as tune the encoder for distortion metric. + ], + ], + + /* + * These generators will be used to create an image of media files. + */ + 'image_generators' => [ + Spatie\MediaLibrary\Conversions\ImageGenerators\Image::class, + Spatie\MediaLibrary\Conversions\ImageGenerators\Webp::class, + Spatie\MediaLibrary\Conversions\ImageGenerators\Avif::class, + Spatie\MediaLibrary\Conversions\ImageGenerators\Pdf::class, + Spatie\MediaLibrary\Conversions\ImageGenerators\Svg::class, + Spatie\MediaLibrary\Conversions\ImageGenerators\Video::class, + ], + + /* + * The path where to store temporary files while performing image conversions. + * If set to null, storage_path('media-library/temp') will be used. + */ + 'temporary_directory_path' => null, + + /* + * The engine that should perform the image conversions. + * Should be either `gd`, `imagick` or `vips`. + */ + 'image_driver' => env('IMAGE_DRIVER', 'gd'), + + /* + * FFMPEG & FFProbe binaries paths, only used if you try to generate video + * thumbnails and have installed the php-ffmpeg/php-ffmpeg composer + * dependency. + */ + 'ffmpeg_path' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'), + 'ffprobe_path' => env('FFPROBE_PATH', '/usr/bin/ffprobe'), + + /* + * The timeout (in seconds) that will be used when generating video + * thumbnails via FFMPEG. + */ + 'ffmpeg_timeout' => env('FFMPEG_TIMEOUT', 900), + + /* + * The number of threads that FFMPEG should use. 0 means that FFMPEG + * may decide itself. + */ + 'ffmpeg_threads' => env('FFMPEG_THREADS', 0), + + /* + * Here you can override the class names of the jobs used by this package. Make sure + * your custom jobs extend the ones provided by the package. + */ + 'jobs' => [ + 'perform_conversions' => Spatie\MediaLibrary\Conversions\Jobs\PerformConversionsJob::class, + 'generate_responsive_images' => Spatie\MediaLibrary\ResponsiveImages\Jobs\GenerateResponsiveImagesJob::class, + ], + + /* + * When using the addMediaFromUrl method you may want to replace the default downloader. + * This is particularly useful when the url of the image is behind a firewall and + * need to add additional flags, possibly using curl. + */ + 'media_downloader' => Spatie\MediaLibrary\Downloaders\DefaultDownloader::class, + + /* + * When using the addMediaFromUrl method the SSL is verified by default. + * This is option disables SSL verification when downloading remote media. + * Please note that this is a security risk and should only be false in a local environment. + */ + 'media_downloader_ssl' => env('MEDIA_DOWNLOADER_SSL', true), + + /* + * The default lifetime in minutes for temporary urls. + * This is used when you call the `getLastTemporaryUrl` or `getLastTemporaryUrl` method on a media item. + */ + 'temporary_url_default_lifetime' => env('MEDIA_TEMPORARY_URL_DEFAULT_LIFETIME', 5), + + 'remote' => [ + /* + * Any extra headers that should be included when uploading media to + * a remote disk. Even though supported headers may vary between + * different drivers, a sensible default has been provided. + * + * Supported by S3: CacheControl, Expires, StorageClass, + * ServerSideEncryption, Metadata, ACL, ContentEncoding + */ + 'extra_headers' => [ + 'CacheControl' => 'max-age=604800', + ], + ], + + 'responsive_images' => [ + /* + * This class is responsible for calculating the target widths of the responsive + * images. By default we optimize for filesize and create variations that each are 30% + * smaller than the previous one. More info in the documentation. + * + * https://docs.spatie.be/laravel-medialibrary/v9/advanced-usage/generating-responsive-images + */ + 'width_calculator' => Spatie\MediaLibrary\ResponsiveImages\WidthCalculator\FileSizeOptimizedWidthCalculator::class, + + /* + * By default rendering media to a responsive image will add some javascript and a tiny placeholder. + * This ensures that the browser can already determine the correct layout. + * When disabled, no tiny placeholder is generated. + */ + 'use_tiny_placeholders' => true, + + /* + * This class will generate the tiny placeholder used for progressive image loading. By default + * the media library will use a tiny blurred jpg image. + */ + 'tiny_placeholder_generator' => Spatie\MediaLibrary\ResponsiveImages\TinyPlaceholderGenerator\Blurred::class, + ], + + /* + * When enabling this option, a route will be registered that will enable + * the Media Library Pro Vue and React components to move uploaded files + * in a S3 bucket to their right place. + */ + 'enable_vapor_uploads' => env('ENABLE_MEDIA_LIBRARY_VAPOR_UPLOADS', false), + + /* + * When converting Media instances to response the media library will add + * a `loading` attribute to the `img` tag. Here you can set the default + * value of that attribute. + * + * Possible values: 'lazy', 'eager', 'auto' or null if you don't want to set any loading instruction. + * + * More info: https://css-tricks.com/native-lazy-loading/ + */ + 'default_loading_attribute_value' => null, + + /* + * You can specify a prefix for that is used for storing all media. + * If you set this to `/my-subdir`, all your media will be stored in a `/my-subdir` directory. + */ + 'prefix' => env('MEDIA_PREFIX', ''), + + /* + * When forcing lazy loading, media will be loaded even if you don't eager load media and you have + * disabled lazy loading globally in the service provider. + */ + 'force_lazy_loading' => env('FORCE_MEDIA_LIBRARY_LAZY_LOADING', true), +]; diff --git a/public/css/asmit/filament-upload/filepond-pdf.css b/public/css/asmit/filament-upload/filepond-pdf.css new file mode 100644 index 0000000..5d71c0a --- /dev/null +++ b/public/css/asmit/filament-upload/filepond-pdf.css @@ -0,0 +1,56 @@ +.filepond--pdf-preview-wrapper { + background: #00000003; + border-radius: 0.45em; + height: 100%; + left: 0; + margin: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.filepond--pdf-preview { + align-items: center; + background: #222; + display: flex; + height: 100%; + left: 0; + /* pointer-events: none; */ + position: absolute; + top: 0; + width: 100%; + will-change: transform, opacity; + z-index: 1; +} + +.filepond--pdf-preview-iframe { + position: absolute; + left: 0; + right: 0; + margin: auto; + width: 100%; + padding-top: unset; + transform: scale(1.05); +} + +.filepond--overlay-shadow { + background: linear-gradient(to bottom, #282828d9 0%, transparent 100%); + mix-blend-mode: multiply; + width: 100%; + height: 4rem; + position: absolute; + left: 0; + z-index: 2; +} + +.filepond--overlay-shadow.overlay-shadow--success { + background: linear-gradient(to bottom, #369763 0%, transparent 100%); +} + +.filepond--overlay-shadow.overlay-shadow--failure { + background: linear-gradient(to bottom, #c44e47 0%, transparent 100%); +} diff --git a/public/js/asmit/filament-upload/components/filepond-pdf.js b/public/js/asmit/filament-upload/components/filepond-pdf.js new file mode 100644 index 0000000..28e4c55 --- /dev/null +++ b/public/js/asmit/filament-upload/components/filepond-pdf.js @@ -0,0 +1 @@ +var u=r=>r.type==="application/pdf",y=r=>new URLSearchParams({toolbar:r.query("GET_PDF_TOOLBAR")?1:0,navpanes:r.query("GET_PDF_NAVPANE")?1:0,statusbar:r.query("GET_PDF_STATUS_BAR")?1:0,zoom:r.query("GET_PDF_ZOOM")?1:0,view:r.query("GET_PDF_VIEW"),scrollbar:r.query("GET_PDF_SCROLLBAR")?1:0,page:r.query("GET_PDF_DISPLAY_PAGE")}),I=r=>{let a=({root:e,props:n})=>{let{id:c}=n,t=e.query("GET_ITEM",c),p=y(e),d=()=>{if(typeof t.source!="string"){let i=window.URL||window.webkitURL,l=new Blob([t.file],{type:t.file.type});return i.createObjectURL(l)}return t.source};e.ref.pdf.src=`${d()}#${p.toString()}`,e.ref.pdf.addEventListener("load",()=>{e.dispatch("DID_UPDATE_PANEL_HEIGHT",{id:c,height:e.ref.pdf.scrollHeight})},!1)},s=({root:e,props:n})=>{e.query("GET_ITEM",n.id).file&&(e.ref.pdf=document.createElement("iframe"),e.ref.pdf.setAttribute("height",e.query("GET_PDF_PREVIEW_HEIGHT")||320),e.ref.pdf.classList.add("filepond--pdf-preview-iframe"),e.element.appendChild(e.ref.pdf))};return r.createView({name:"pdf-preview",tag:"div",create:s,write:r.createRoute({DID_PDF_PREVIEW_LOAD:a})})},T=r=>r.createView({name:"overlay-shadow",tag:"div",ignoreRect:!0,create:({root:a,props:s})=>{a.element.classList.add(`overlay-shadow--${s.status}`)},mixins:{styles:["opacity"],animations:{opacity:{type:"spring",mass:25}}}}),D=r=>{let a=r.utils,s=I(a),e=T(a),n=({root:i,props:l})=>{let{id:f}=l;i.dispatch("DID_PDF_PREVIEW_LOAD",{id:f})},c=({root:i,props:l})=>{i.ref.overlayShadow=i.appendChildView(i.createChildView(e,{opacity:1,status:"idle"})),i.ref.overlaySuccess=i.appendChildView(i.createChildView(e,{opacity:0,status:"success"})),i.ref.overlayError=i.appendChildView(i.createChildView(e,{opacity:0,status:"failure"})),i.ref.pdf=i.appendChildView(i.createChildView(s,{id:l.id}))},t=({root:i})=>{i.ref.overlayShadow.opacity=1,i.ref.overlayError.opacity=0,i.ref.overlaySuccess.opacity=0},p=({root:i,props:l})=>{i.ref.overlayShadow.opacity=.1,i.ref.overlayError.opacity=1},d=({root:i,props:l})=>{i.ref.overlayShadow.opacity=.1,i.ref.overlaySuccess.opacity=1};return a.createView({name:"pdf-preview-wrapper",tag:"div",create:c,write:a.createRoute({DID_CREATE_PDF_PREVIEW_CONTAINER_VIEW:n,DID_THROW_ITEM_LOAD_ERROR:p,DID_THROW_ITEM_PROCESSING_ERROR:p,DID_THROW_ITEM_INVALID:p,DID_COMPLETE_ITEM_PROCESSING:d,DID_START_ITEM_PROCESSING:t,DID_REVERT_ITEM_PROCESSING:t})})},v=r=>{let{addFilter:a,utils:s}=r,{Type:e,createRoute:n}=s,c=D(r);return a("CREATE_VIEW",t=>{let{is:p,view:d,query:i}=t;if(!p("file"))return;let l=({root:f,props:w})=>{let{id:E}=w,_=i("GET_ITEM",E),o=i("GET_ALLOW_PDF_PREVIEW");!_||!u(_?.file)||_?.archived||!o||(f.ref.pdfPreview=d.appendChildView(d.createChildView(c,{id:E})),f.dispatch("DID_CREATE_PDF_PREVIEW_CONTAINER_VIEW",{id:E}))};d.registerWriter(n({DID_LOAD_ITEM:l}),(f,w)=>{f.ref.pdfPreview&&f.rect.element.hidden})}),{options:{allowPdfPreview:[!0,e.BOOLEAN],pdfPreviewHeight:[400,e.INT],pdfToolbar:[!1,e.BOOLEAN],pdfNavPanes:[!1,e.BOOLEAN],pdfStatusBar:[!1,e.BOOLEAN],pdfZoom:[!1,e.BOOLEAN],pdfView:["fitW",e.STRING],pdfDisplayPage:[1,e.INT]}}},P=v;function R({pdfPreviewHeight:r,pdfScrollbar:a,pdfDisplayPage:s,pdfToolbar:e,pdfNavPanes:n,pdfZoom:c,pdfView:t,allowPdfPreview:p}){document.addEventListener("FilePond:loaded",function(){let d=window.FilePond;d.registerPlugin(P),d.setOptions({pdfPreviewHeight:r,pdfScrollbar:a,pdfDisplayPage:s,pdfToolbar:e,pdfNavPanes:n,pdfZoom:c,pdfView:t,allowPdfPreview:p})})}export{R as default}; diff --git a/resources/views/vendor/media-library/image.blade.php b/resources/views/vendor/media-library/image.blade.php new file mode 100644 index 0000000..b2ea05b --- /dev/null +++ b/resources/views/vendor/media-library/image.blade.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/views/vendor/media-library/placeholderSvg.blade.php b/resources/views/vendor/media-library/placeholderSvg.blade.php new file mode 100644 index 0000000..1ba86f8 --- /dev/null +++ b/resources/views/vendor/media-library/placeholderSvg.blade.php @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/views/vendor/media-library/responsiveImage.blade.php b/resources/views/vendor/media-library/responsiveImage.blade.php new file mode 100644 index 0000000..27c4a92 --- /dev/null +++ b/resources/views/vendor/media-library/responsiveImage.blade.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/views/vendor/media-library/responsiveImageWithPlaceholder.blade.php b/resources/views/vendor/media-library/responsiveImageWithPlaceholder.blade.php new file mode 100644 index 0000000..f49e54f --- /dev/null +++ b/resources/views/vendor/media-library/responsiveImageWithPlaceholder.blade.php @@ -0,0 +1 @@ +