Skip to content

Latest commit

 

History

30 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

media_uploader_screenshot

Livewire Media Uploader

tests

Livewire Media Uploader is a reusable Livewire v3/v4 component that integrates seamlessly with Spatie Laravel Media Library. It ships a clean Tailwind Blade view by default (fully publishable), Bootstrap theme as an option, Alpine overlays for previews/confirmations, drag-and-drop uploads, per-file metadata (caption/description/order), configurable presets, image watermarking, name-conflict strategies, and optional SHA-256 duplicate detection. Drop it in, point it at a model, and you’re shipping in minutes.


Table of Contents


Features

  • ✅ Livewire v3/v4 component with themeable Blade UI
    • Tailwind (default)
    • Bootstrap (optional)
    • Fully publishable and overridable
  • ✅ Spatie Media Library integration (attach, list, edit meta, delete)
  • ✅ Publishable view for per-project customization
  • ✅ Drag & drop uploads + progress bar
  • ✅ Inline edit of caption / description / order
  • ✅ Drag-to-reorder attached media (order_column)
  • ✅ Name-conflict strategies: rename | replace | skip | allow
  • ✅ Optional exact duplicate detection via SHA-256
  • ✅ Optional server-side image watermarking with configurable placement, size, padding, and opacity
  • ✅ Collection → preset mapping (auto accept attribute)
  • ✅ Image preview overlay + delete confirmation modal
  • ✅ Optional authorization hook (authorizeAbility) — delegates to your app's own Gate/Policy, no auth package required
  • ✅ Works with:
    • Saved model instance (:for="$model")
    • String model + id (model="user" :id="1")
    • FQCN, morph map alias, or dotted paths with custom namespaces
    • Local alias map

Requirements

  • PHP 8.2+
  • Laravel ^12.0 | ^13.0
  • Livewire ^3.8.3 | ^4.3.4
  • spatie/laravel-medialibrary ^11.0
  • spatie/image ^3.3.2
  • TailwindCSS (optional but recommended for the default view)
  • Alpine.js (used by overlays/progress; see Overlays & UX Notes)
  • CSS depending on theme:
    • Tailwind theme → TailwindCSS (recommended)
    • Bootstrap theme → Bootstrap CSS (no Bootstrap JS required; Alpine drives modals)

Note on Laravel 10/11: Earlier releases of this package listed Laravel 10 and 11 as supported. Both are now past their security-support window (Laravel 10 is EOL; Laravel 11 security support ended March 2026), and current releases of laravel/framework in those lines carry known, unpatched advisories — meaning a fresh composer install targeting either will be blocked by Composer's own audit for most consumers. Support for both has been dropped as of v0.5.0. If you're still running Laravel 10/11, pin this package to v0.4.x, but prioritize upgrading Laravel first — that's the more urgent fix.

Every PHP/Laravel/Livewire combination listed above is verified on every push via GitHub Actions.


Installation

composer require codebyray/livewire-media-uploader

Auto-discovery will register the service provider. If you disable discovery, add:

// config/app.php
'providers' => [
    // ...
    Codebyray\LivewireMediaUploader\MediaUploaderServiceProvider::class,
],

The component is registered under both aliases:

  • <livewire:media-uploader ... />
  • <livewire:media.media-uploader ... />

Publishing Assets

Config:

php artisan vendor:publish --tag=media-uploader-config

Views:

php artisan vendor:publish --tag=media-uploader-views

After publishing, customize the Blade at:

resources/views/vendor/media-uploader/themes/tailwind/media-uploader.blade.php
resources/views/vendor/media-uploader/themes/bootstrap/media-uploader.blade.php

Theme System (Tailwind + Bootstrap + custom)

Select the theme in config/media-uploader.php:

// config/media-uploader.php
return [
    'theme'  => 'tailwind', // 'tailwind' (default) or 'bootstrap'
    'themes' => [
        'tailwind'  => 'media-uploader::themes.tailwind.media-uploader',
        'bootstrap' => 'media-uploader::themes.bootstrap.media-uploader',
    ],
    // ...
];

Dark mode (Tailwind theme)

This package’s Tailwind theme is dark-ready. Add this tiny snippet in your main layout <head> to apply the user’s saved choice / system default:

<script>
    (() => {
        const t = localStorage.theme ?? 'system';
        const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
        const dark = t === 'dark' || (t === 'system' && prefersDark);
        if (dark) document.documentElement.classList.add('dark');
    })();
</script>

Custom themes

  • Copy an existing theme directory (e.g. themes/tailwind) to themes/custom and edit the Blade.
  • Register it in the map and select it:
    'theme'  => 'custom',
    'themes' => [
        'tailwind'  => 'media-uploader::themes.tailwind.media-uploader',
        'bootstrap' => 'media-uploader::themes.bootstrap.media-uploader',
        'custom'    => 'media-uploader::themes.custom.media-uploader',
    ],

    Note: The component’s Livewire + Alpine behavior is identical across themes. Only classes/markup differ. If you use the Bootstrap theme, make sure your layout includes Bootstrap CSS.

Environment variables (optional)

You can override preset limits and accepted types/mimes via .env. These map directly to config/media-uploader.php:

# Livewire Media Uploader (optional)

# Images
MEDIA_TYPES_IMAGES=jpg,jpeg,png,webp,avif,gif
MEDIA_MIMES_IMAGES=image/jpeg,image/png,image/webp,image/avif,image/gif
MEDIA_MAXKB_IMAGES=10240

# Documents
MEDIA_TYPES_DOCS=pdf,doc,docx,xls,xlsx,ppt,pptx,txt
MEDIA_MIMES_DOCS=application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,text/plain
MEDIA_MAXKB_DOCS=20480

# Videos
MEDIA_TYPES_VIDEOS=mp4,mov,webm
MEDIA_MIMES_VIDEOS=video/mp4,video/quicktime,video/webm
MEDIA_MAXKB_VIDEOS=102400

# Fallback preset
MEDIA_TYPES_DEFAULT=jpg,jpeg,png,webp,avif,gif,pdf,doc,docx,xls,xlsx,ppt,pptx,txt
MEDIA_MIMES_DEFAULT=image/jpeg,image/png,image/webp,image/avif,image/gif,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,text/plain
MEDIA_MAXKB_DEFAULT=10240

# Image watermarking
MEDIA_UPLOADER_WATERMARK_ENABLED=false
MEDIA_UPLOADER_WATERMARK_PATH=/absolute/path/to/watermark.png

Notes

  • Values are comma-separated; spaces are OK (the package trims them).
  • After changing .env, run:
    php artisan config:clear
  • The <input accept="…"> attribute is auto-filled from the active preset when accept_from_config is true (default). You can still override it per-component with the accept prop.
  • If uploads fail due to size, make sure your PHP/Server limits also allow it (e.g. upload_max_filesize, post_max_size).

Quick Start

  1. Ensure your target Eloquent model implements Spatie\MediaLibrary\HasMedia and is saved.

    Model Setup (Spatie Media Library)

    Your model must implement HasMedia and be saved before attaching media.

    use Spatie\Image\Enums\Fit;
    use Spatie\MediaLibrary\HasMedia;
    use Spatie\MediaLibrary\InteractsWithMedia;
    use Spatie\MediaLibrary\MediaCollections\Models\Media;
    
    class Post extends Model implements HasMedia
    {
        use InteractsWithMedia;
    
        public function registerMediaCollections(): void
        {
            // Multi-file collection.
            $this->addMediaCollection('photos')
                ->useDisk('public')
                ->withResponsiveImages();
    
            // Single-file collection. Each new upload replaces the existing file.
            $this->addMediaCollection('avatars')
                ->singleFile();
        }
    
        public function registerMediaConversions(?Media $media = null): void
        {
            $this->addMediaConversion('thumb')
                ->fit(Fit::Contain, 256, 256)
                ->performOnCollections('photos', 'avatars')
                ->nonQueued();
        }
    }

    Multiple uploads and singleFile()

    The uploader's multiple prop controls whether the file input allows selecting multiple files. It does not override Spatie Media Library's collection configuration.

    If a collection is configured with ->singleFile(), Spatie will remove the existing media item each time another file is added. Selecting multiple files can therefore process every selected file while leaving only the last file in the collection.

    For galleries and other multi-file collections, do not use ->singleFile():

    $this->addMediaCollection('photos');

    Use ->singleFile() only when the collection should contain one item, such as an avatar or logo:

    $this->addMediaCollection('avatar')
        ->singleFile();
  2. Include Livewire & Alpine (usually in your app layout):

    @livewireStyles
    <style>[x-cloak]{ display:none !important; }</style>
    @livewireScripts
  3. Drop the component into your Blade:

    <livewire:media-uploader :for="$user" collection="avatars" preset="images" />

Usage Examples

  1. Pass a saved model instance

    <livewire:media-uploader :for="$user" collection="avatars" preset="images" />
  2. Short string model + id

    <livewire:media-uploader model="user" :id="$user->id" collection="images" preset="images" />
  3. Morph map alias**

    <livewire:media-uploader model="users" :id="$user->id" collection="profile" preset="images" />
  4. FQCN

    <livewire:media-uploader model="\App\Models\User" :id="$user->id" collection="documents" />
  5. Dotted path + custom namespaces

    <livewire:media-uploader
        model="crm.contact"
        :id="$contactId"
        :namespaces="['App\\Domain\\Crm\\Models', 'App\\Models']"
        collection="images"
        preset="images"
    />
  6. Local aliases (per-instance)

    <livewire:media-uploader
        model="profile"
        :id="$user->id"
        :aliases="['profile' => \App\Models\User::class]"
        collection="gallery"
    />
  7. Single-file mode + hide list

    <livewire:media-uploader
        :for="$user"
        collection="avatar"
        :multiple="false"
        :showList="false"
        preset="images"
    />
  8. Name conflict strategies

    <livewire:media-uploader :for="$user" collection="files" onNameConflict="rename" />
    <livewire:media-uploader :for="$user" collection="files" onNameConflict="replace" />
    <livewire:media-uploader :for="$user" collection="files" onNameConflict="skip" />
    <livewire:media-uploader :for="$user" collection="files" onNameConflict="allow" />
  9. Duplicate detection by SHA-256

    <livewire:media-uploader :for="$user" collection="images" preset="images" :skipExactDuplicates="true" />
  10. Restrict types/mimes/max size manually

    <livewire:media-uploader
        :for="$user"
        collection="documents"
        :accept="'.pdf,.doc,.docx,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'"
        :allowedTypes="['pdf','doc','docx']"
        :allowedMimes="['application/pdf','application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document']"
        :maxSizeKb="5120"
    />
  11. Watermark image uploads

    <livewire:media-uploader
        :for="$post"
        collection="images"
        preset="images"
        :watermark="true"
    />

    See Watermarking for setup, every available option, and processing behavior.

Create flow (deferred uploads)

You can let users pick files before the model exists, and attach them after save.

Blade (create page)

<!-- Note: pass model class/alias without id -->
<livewire:media-uploader
    model="post"
    collection="images"
    preset="images"
    :multiple="true"
    :showList="true"
/>

Livewire component (simplified)

use App\Models\Post;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\On;
use Livewire\Component;

class PostCreate extends Component
{
    public string $title = '';
    public string $body  = '';
    public ?int $pendingPostId = null;

    protected function rules(): array
    {
        return ['title' => 'required|string|max:255', 'body' => 'required|string'];
    }

    public function save(): void
    {
        $post = Post::create([
            'user_id' => Auth::id(),
            'title'   => $this->title,
            'body'    => $this->body,
        ]);

        // Let uploaders attach everything queued for this collection
        $this->pendingPostId = $post->id;

        // Fire once per collection rendered on the page
        $this->dispatch('media:attach', model: 'post', id: $post->id, collection: 'images');
    }

    #[On('media-attached')]
    public function afterMediaAttached(string $model, string|int $id): void
    {
        if ($this->pendingPostId && (int)$id === (int)$this->pendingPostId) {
            $this->pendingPostId = null;
            $this->redirectRoute('posts.show', ['post' => $id], navigate: true);
        }
    }

    public function render() { return view('livewire.posts.post-create'); }
}

How it works

  • On create screens, the component accepts model="post" without an id.
  • Files and per-file metadata are queued locally.
  • After you persist the model, dispatch:
    $this->dispatch('media:attach', model: 'post', id: $post->id, collection: 'images');
  • The uploader resolves the saved target, attaches any queued files, and emits media-attached.

Configuration

Publish the package configuration before customizing global behavior:

php artisan vendor:publish --tag=media-uploader-config

The published file is config/media-uploader.php. Laravel automatically merges the package defaults when the file has not been published.

Configuration reference

Key Default Purpose
model_namespaces ['App\\Models'] Namespaces searched when resolving short or dotted model names. They are checked in array order.
theme tailwind Default theme key. It must exist in the themes map. Set it with MEDIA_UPLOADER_THEME or override it using the component's theme prop.
themes Tailwind and Bootstrap views Maps theme keys to fully qualified Blade view names. Add published custom themes here.
accept_from_config true Builds the file input's accept attribute from the active preset's MIME types and extensions. This is a browser hint; server validation still runs independently.
watermark Disabled Controls image watermark processing. See Watermarking.
collections Common collection mappings Maps a Media Library collection name to a validation preset.
presets images, docs, videos, default Defines reusable upload validation and file-picker rules.

Collection and preset resolution

Collections and presets are separate concepts. collection="avatars" selects the Spatie Media Library collection, while the collection map selects which validation preset applies:

'collections' => [
    'avatars' => 'images',
    'images' => 'images',
    'attachments' => 'docs',
],

For collection="avatars", the component uses the images preset unless the component receives an explicit preset prop.

The active preset is resolved in this order:

  1. The component's explicit preset prop.
  2. The preset mapped from the active collection in collections.
  3. The default preset.

Each preset supports:

Key Meaning
types Comma-separated filename extensions. These are used for validation and, when enabled, the input's accept attribute.
mimes Comma-separated MIME types used for server-side validation and the generated accept attribute.
max_kb Maximum size of each uploaded file in kilobytes. PHP, the web server, and Livewire upload limits must also allow this size.

You can add your own preset and map any collection to it:

'collections' => [
    'press-kits' => 'archives',
],

'presets' => [
    'archives' => [
        'types' => 'zip',
        'mimes' => 'application/zip',
        'max_kb' => 51200,
    ],
],

The built-in preset values can be overridden through the environment variables listed in Environment variables. After changing configuration in a cached production application, run php artisan config:clear or rebuild the configuration cache.

Showing every collection

Set :list-all="true" to render a grouped list of every collection on the target model. Items remain editable, and ordering stays scoped to each collection.

<livewire:media-uploader
    :for="$post"
    :list-all="true"
    :showList="true"
/>

Watermarking

Watermarking is disabled by default. When enabled, the uploader composites a server-side image over each uploaded image before passing the file to Spatie Media Library. The stored original and any Media Library conversions generated from it therefore contain the watermark. Documents, videos, and other non-image uploads are not changed.

Configure the watermark

Publish config/media-uploader.php, place a watermark image somewhere readable by PHP, and configure the complete watermark section:

'watermark' => [
    'enabled' => (bool) env('MEDIA_UPLOADER_WATERMARK_ENABLED', false),
    'path' => env(
        'MEDIA_UPLOADER_WATERMARK_PATH',
        public_path('images/watermark.png'),
    ),
    'position' => 'bottom-right',
    'padding_x' => 24,
    'padding_y' => 24,
    'padding_unit' => 'pixel',
    'width' => 20,
    'width_unit' => 'percent',
    'height' => 0,
    'height_unit' => 'pixel',
    'fit' => 'contain',
    'opacity' => 70,
],

A transparent PNG is usually the best watermark source. path must resolve to a readable local file; it is not a URL or a filesystem-disk key.

Watermark options

Key Accepted values Description
enabled true or false Global default. An uploader's watermark prop can override it.
path Readable local path Source watermark image. An enabled image upload fails with a clear exception when this is missing or unreadable.
position top-left, top, top-right, left, center, right, bottom-left, bottom, bottom-right Alignment of the watermark within the uploaded image.
padding_x Integer Horizontal distance from the aligned edge.
padding_y Integer Vertical distance from the aligned edge.
padding_unit pixel or percent Unit shared by padding_x and padding_y. Percentage padding is relative to the uploaded image dimensions.
width Integer Desired watermark width. Set to 0 to derive it from height.
width_unit pixel or percent Unit for width. The default 20 percent makes the watermark responsive to source-image width.
height Integer Desired watermark height. Set to 0 to preserve the watermark's aspect ratio from its configured width.
height_unit pixel or percent Unit for height.
fit contain, max, fill, fill-max, stretch, or crop Resize behavior when both width and height are set. With the default height of 0, the original aspect ratio is preserved.
opacity Integer from 0 to 100 Watermark opacity, where 0 is invisible and 100 is fully opaque.

Enable it globally or per uploader

To watermark every image handled by the package, set the global configuration:

MEDIA_UPLOADER_WATERMARK_ENABLED=true
MEDIA_UPLOADER_WATERMARK_PATH=/var/www/example.com/public/images/watermark.png

To enable it only for selected uploaders, leave the global setting disabled and pass :watermark="true":

<livewire:media-uploader
    :for="$post"
    collection="images"
    preset="images"
    :watermark="true"
/>

To disable it for one uploader when the global setting is enabled, pass :watermark="false":

<livewire:media-uploader
    :for="$post"
    collection="private-images"
    preset="images"
    :watermark="false"
/>

The prop is optional. When omitted, the uploader uses watermark.enabled from configuration. The prop only controls whether processing runs; the path and rendering options remain server-controlled in the configuration file.

Processing behavior and requirements

  • Validation and exact-duplicate detection run before watermark processing.
  • Name-conflict handling and Media Library storage run after the watermark is successfully applied, so a watermark error does not delete an existing file during the replace strategy.
  • Multiple image uploads are processed individually.
  • Deferred create-form uploads are watermarked when the queued files are attached to the saved model.
  • Processing happens on Livewire's local temporary upload before the selected Media Library disk receives the file, including when the destination disk is remote.
  • The package uses the image driver configured by Spatie Media Library in media-library.image_driver. That driver must support both the uploaded format and the watermark format.
  • The uploader never modifies the file on the user's computer; only the server-side temporary upload and stored copy are changed.

Props

Prop Type Default Description
for Model — Saved Eloquent model instance implementing HasMedia.
model string — Model resolver: alias, FQCN, morph alias, or dotted path.
id `int string` —
collection string images Media collection name.
disk ?string null Storage disk (e.g. s3).
multiple bool true Allow selecting multiple files. The target Spatie collection must not use singleFile() if multiple files should be retained.
accept ?string null <input accept> override (otherwise may be auto from config).
showList bool true Show the attached media list.
theme ?string Configured theme Override the globally configured theme for this uploader.
maxSizeKb ?int Active preset's max_kb Max file size (KB). An explicit value overrides the preset.
preset ?string null Choose a preset (images, docs, videos, default, etc.).
allowedTypes array [] Extensions filter (e.g. ['jpg','png']).
allowedMimes array [] MIME filter (e.g. ['image/jpeg']).
onNameConflict string rename Strategy: rename | replace | skip | allow.
skipExactDuplicates bool false Uses SHA-256 stored in custom_properties->sha256.
watermark ?bool Config value Enable or disable watermarking for this uploader instance.
namespaces array ['App\\Models'] Namespaces for dotted-path resolution.
aliases array [] Local alias map, e.g. ['profile' => \App\Models\User::class].
attachedFilesTitle string "Current gallery" Heading text in the list card.
channel ?string null Route deferred media:attach events to a specific uploader. When set, the incoming event must contain the same channel.
listAll bool false When true, the attached media list shows all collections, grouped by collection name (still editable).
authorizeAbility ?string null Gate/Policy ability checked against the target model before upload/delete/edit/attach. See Authorization.

Events

The component dispatches browser events you can listen for:

  • media:attach — incoming event the component listens for. Arguments: model (class/alias), id, optional collection, optional disk, and optional channel. When the uploader has a channel, the event must provide the same value. Triggers attaching queued files to the saved target.
  • media-attached — emitted after a successful media:attach. Payload: { model: FQCN, id: string, channel: ?string }.
  • media-uploaded — emitted after an immediate upload (when a target already exists).
  • media-deleted — emitted after deletion (detail.id contains the Media ID).
  • media-meta-updated — emitted after inline metadata is saved.

Example:

<div
  x-data
  x-on:media-uploaded.window="console.log('uploaded!')"
  x-on:media-deleted.window="console.log('deleted', $event.detail?.id)"
>
  <livewire:media-uploader :for="$user" collection="images" preset="images" />
</div>

Authorization

By default, the component does not perform any authorization. It verifies that a given Media record belongs to the resolved target model before allowing edits/deletes, but it does not check whether the current user is allowed to modify that model. It's your app's responsibility to ensure the component only renders where the user already has access (route middleware, a policy check before rendering the page, etc.).

If you'd like the component to enforce this itself, set authorizeAbility to a Gate/Policy ability name. It's checked against the resolved target model before every mutating action (uploadFiles, remove, saveEdit, and the media:attach event handler), using Laravel's own Gate::authorize() — no extra package required, and it plays nicely with anything already wired up (Policies, Gate closures, Spatie Permissions via a Gate, etc.).

<livewire:media-uploader
    :for="$post"
    collection="images"
    preset="images"
    authorizeAbility="update"
/>

With the example above, before any upload/delete/edit/attach action runs, the component calls the equivalent of Gate::authorize('update', $post). If your PostPolicy::update() returns false, the action aborts with a 403 instead of proceeding.

Notes:

  • One ability is checked for all mutating actions. If you need delete and update to map to different Policy methods, don't set authorizeAbility — instead wrap the component's Blade usage behind your own check, or open an issue/PR describing the use case.
  • The channel prop routes media:attach events to the intended component instance. A configured channel must match exactly, but it is not an authorization boundary. Use authorizeAbility (or your own upstream checks) if untrusted input could influence which model/id gets dispatched.
  • Leaving authorizeAbility unset preserves the exact behavior of versions prior to 0.5.0 — this is a fully backward-compatible, opt-in addition.

The list view tries getUrl('thumb') and falls back to getUrl() if no conversion is available.


Overlays & UX Notes

  • Image Preview Overlay (lightbox): toggled by x-show="preview.open".
  • Delete Confirmation Modal: toggled by $wire.confirmingDeleteId !== null.
  • Add once in your layout to prevent flash-of-overlay:
    <style>[x-cloak]{ display:none !important; }</style>
  • Z-index defaults: preview z-[60], delete modal z-50. Adjust to your stack if you have higher layers.

Troubleshooting

  • “Target model must be saved…”
    Ensure the model exists in DB ($model->exists === true) before rendering the component.

  • “must implement Spatie\MediaLibrary\HasMedia”
    Add implements HasMedia + InteractsWithMedia to your model.

  • Unknown model class/alias
    If using model="something" + :id, make sure:

    • It’s a valid FQCN, morph alias, or maps via dotted path within namespaces, or
    • You passed a local alias via :aliases="['something' => \App\Models\YourModel::class].
  • Multiple files selected, but only one remains after upload
    Check the target model's registerMediaCollections() method. If the collection uses Spatie Media Library's ->singleFile(), each new upload replaces the previous media item.

    For multiple files:

    $this->addMediaCollection('photos');

    For a collection that should contain only one file:

    $this->addMediaCollection('avatar')
      ->singleFile();
  • accept not applied
    Set accept_from_config=true and ensure your preset has types/mimes. Or override via accept prop.

  • No thumbnails
    Add a thumb conversion (see Model Setup).

  • Watermark path is missing or unreadable: Set MEDIA_UPLOADER_WATERMARK_PATH to an absolute readable image path, or configure watermark.path in the published config. Clear or rebuild Laravel's config cache afterward.

  • A watermarked format fails to process: Confirm that the driver selected by media-library.image_driver supports both the uploaded format and the watermark format. GD is available in the package's CI matrix; Imagick or Vips support depends on the consuming application.


Roadmap

  • Show document icon instead of thumbnail in Attached media list if the file is not an image.

PRs welcome!


License

MIT © CodebyRay (Ray Cuzzart II)


Component aliases: media-uploader and media.media-uploader
View namespace: media-uploader::livewire.media-uploader

About

Drop-in Livewire media uploader for Laravel with Spatie Media Library: drag-and-drop, presets, metadata, SHA-256 duplicate detection, and a publishable Blade view.

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages