{{-- ============================================================ IMAGE UPLOADER COMPONENT ============================================================ LOCATION : resources/views/components/image-uploader.blade.php USAGE — Create page: USAGE — Edit page: PROPS: existing — array of saved paths from DB (default: []) maxFiles — max number of images (default: 10) maxSizeMb — max MB per image (default: 5) name — file input name (default: device_images) ADD IN LAYOUT : ADD BEFORE : ============================================================ --}} @props([ 'existing' => [], 'maxFiles' => 10, 'maxSizeMb' => 5, 'name' => 'device_images', ]) {{-- ── Hidden file input ────────────────────────────────────── Kept OUTSIDE the drop zone on purpose. Using native inputEl.click() (not jQuery trigger) avoids the "too much recursion" infinite loop bug. ─────────────────────────────────────────────────────────── --}} {{-- Hidden inputs injected by JS when user marks an existing image for deletion. Sent to controller as delete_images[] --}}
{{-- ── Config bridge ───────────────────────────────────────── Blade props cannot go into a .js file, so we pass them via data-* attributes on a single element. The JS file reads these attributes with dataset and needs no inline Blade. ─────────────────────────────────────────────────────────── --}}
{{-- ── Upload Card ─────────────────────────────────────────── --}}
{{-- Drop Zone --}}

{{ __('app.drag_drop_images_here') }}

{{ __('app.supported_image_formats') }} — max {{ $maxFiles }} images, {{ $maxSizeMb }} MB each

0 / {{ $maxFiles }}
{{-- /drop-zone --}} {{-- Warnings --}}
{!! __('app.max_images_allowed', ['maxFiles' => $maxFiles]) !!}
{{ __('app.some_files_skipped_only_images_allowed') }}
{{ __('app.some_files_skipped_max_size_exceeded', ['maxSizeMb' => $maxSizeMb]) }}
{{-- /card --}} {{-- ── Thumbnail strip ─────────────────────────────────────── --}}
{{-- ── Action bar (visible only when new images are queued) ── --}}
0 new image(s) queued