541 lines
26 KiB
PHP
541 lines
26 KiB
PHP
<?php
|
||
|
||
use App\Models\DisplayMedia;
|
||
use App\Services\DisplayMediaService;
|
||
use Flux\Flux;
|
||
use Illuminate\Support\Facades\Storage;
|
||
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
||
use Livewire\WithFileUploads;
|
||
use function Livewire\Volt\{layout, title, state, computed, on, uses};
|
||
|
||
layout('components.layouts.app');
|
||
title('Display-Mediathek');
|
||
uses([WithFileUploads::class]);
|
||
|
||
state([
|
||
'search' => '',
|
||
'filterType' => 'all',
|
||
'filterSource' => 'all',
|
||
'filterCollection' => '',
|
||
'viewMode' => 'grid',
|
||
'editingId' => null,
|
||
'editTitle' => '',
|
||
'editAltText' => '',
|
||
'editCollection' => '',
|
||
'showDetail' => false,
|
||
// Upload
|
||
'uploads' => [],
|
||
// External URL form
|
||
'showUrlModal' => false,
|
||
'urlInput' => '',
|
||
'urlType' => 'video',
|
||
'urlTitle' => '',
|
||
'urlCollection' => '',
|
||
'urlValidated' => null,
|
||
]);
|
||
|
||
$media = computed(
|
||
fn () => DisplayMedia::query()
|
||
->when($this->filterType !== 'all', fn ($q) => match ($this->filterType) {
|
||
'image' => $q->images(),
|
||
'video' => $q->videos(),
|
||
default => $q,
|
||
})
|
||
->when($this->filterSource !== 'all', fn ($q) => match ($this->filterSource) {
|
||
'upload' => $q->uploads(),
|
||
'external' => $q->externals(),
|
||
default => $q,
|
||
})
|
||
->when($this->filterCollection, fn ($q) => $q->inCollection($this->filterCollection))
|
||
->when($this->search, fn ($q) => $q->where('filename', 'like', "%{$this->search}%")
|
||
->orWhere('title', 'like', "%{$this->search}%"))
|
||
->orderByDesc('created_at')
|
||
->paginate(48),
|
||
);
|
||
|
||
$collections = computed(fn () => DisplayMedia::query()
|
||
->whereNotNull('collection')
|
||
->where('collection', '!=', '')
|
||
->distinct()
|
||
->pluck('collection')
|
||
->sort()
|
||
->values()
|
||
->toArray());
|
||
|
||
$stats = computed(fn () => [
|
||
'total' => DisplayMedia::count(),
|
||
'images' => DisplayMedia::images()->count(),
|
||
'videos' => DisplayMedia::videos()->count(),
|
||
'uploads' => DisplayMedia::uploads()->count(),
|
||
'externals' => DisplayMedia::externals()->count(),
|
||
]);
|
||
|
||
// ========================================
|
||
// FILE UPLOAD
|
||
// ========================================
|
||
|
||
$handleUploads = function () {
|
||
$this->validate([
|
||
'uploads' => 'nullable|array|max:10',
|
||
'uploads.*' => 'file|mimes:jpeg,jpg,png,gif,webp,svg,mp4,webm,mov|max:204800',
|
||
]);
|
||
|
||
$service = app(DisplayMediaService::class);
|
||
$count = 0;
|
||
|
||
foreach ($this->uploads as $file) {
|
||
$service->storeUpload($file);
|
||
$count++;
|
||
}
|
||
|
||
$this->uploads = [];
|
||
|
||
if ($count > 0) {
|
||
Flux::toast(variant: 'success', heading: 'Hochgeladen', text: "{$count} Datei(en) erfolgreich hochgeladen.");
|
||
}
|
||
};
|
||
|
||
// ========================================
|
||
// EXTERNAL URL
|
||
// ========================================
|
||
|
||
$openUrlModal = function () {
|
||
$this->urlInput = '';
|
||
$this->urlType = 'video';
|
||
$this->urlTitle = '';
|
||
$this->urlCollection = '';
|
||
$this->urlValidated = null;
|
||
$this->showUrlModal = true;
|
||
};
|
||
|
||
$validateUrl = function () {
|
||
$this->validate(['urlInput' => 'required|url|max:2048']);
|
||
$service = app(DisplayMediaService::class);
|
||
$this->urlValidated = $service->validateExternalUrl($this->urlInput);
|
||
};
|
||
|
||
$saveExternalUrl = function () {
|
||
$this->validate([
|
||
'urlInput' => 'required|url|max:2048',
|
||
'urlType' => 'required|in:image,video',
|
||
'urlTitle' => 'nullable|string|max:255',
|
||
]);
|
||
|
||
$service = app(DisplayMediaService::class);
|
||
$service->createFromUrl(
|
||
url: $this->urlInput,
|
||
type: $this->urlType,
|
||
title: $this->urlTitle ?: null,
|
||
collection: $this->urlCollection ?: null,
|
||
);
|
||
|
||
$this->showUrlModal = false;
|
||
Flux::toast(variant: 'success', heading: 'Externe URL angelegt', text: 'Das Medium wurde als externe Referenz gespeichert.');
|
||
};
|
||
|
||
// ========================================
|
||
// DETAIL / EDIT
|
||
// ========================================
|
||
|
||
$startEdit = function (int $id) {
|
||
$media = DisplayMedia::find($id);
|
||
if (! $media) {
|
||
return;
|
||
}
|
||
$this->editingId = $id;
|
||
$this->editTitle = $media->title ?? '';
|
||
$this->editAltText = $media->alt_text ?? '';
|
||
$this->editCollection = $media->collection ?? '';
|
||
$this->showDetail = true;
|
||
};
|
||
|
||
$saveEdit = function () {
|
||
$media = DisplayMedia::find($this->editingId);
|
||
if (! $media) {
|
||
return;
|
||
}
|
||
|
||
$media->update([
|
||
'title' => $this->editTitle ?: null,
|
||
'alt_text' => $this->editAltText ?: null,
|
||
'collection' => $this->editCollection ?: null,
|
||
]);
|
||
|
||
Flux::toast(variant: 'success', heading: 'Gespeichert', text: 'Medien-Details wurden aktualisiert.');
|
||
};
|
||
|
||
$deleteMedia = function (int $id) {
|
||
$media = DisplayMedia::find($id);
|
||
if (! $media) {
|
||
return;
|
||
}
|
||
|
||
$filename = $media->getDisplayName();
|
||
$service = app(DisplayMediaService::class);
|
||
$service->delete($media);
|
||
|
||
$this->editingId = null;
|
||
$this->showDetail = false;
|
||
|
||
Flux::toast(variant: 'success', heading: 'Gelöscht', text: $filename . ' wurde entfernt.');
|
||
};
|
||
|
||
$closeDetail = function () {
|
||
$this->showDetail = false;
|
||
$this->editingId = null;
|
||
};
|
||
|
||
?>
|
||
|
||
<div>
|
||
<div class="mb-6 flex items-center justify-between">
|
||
<div>
|
||
<flux:heading size="xl">Display-Mediathek</flux:heading>
|
||
<flux:text class="mt-1">Bilder, Videos und externe URLs für Store Displays verwalten.</flux:text>
|
||
</div>
|
||
<div class="flex items-center gap-3">
|
||
<flux:badge color="sky">{{ $this->stats['images'] }} Bilder</flux:badge>
|
||
<flux:badge color="purple">{{ $this->stats['videos'] }} Videos</flux:badge>
|
||
<flux:badge color="blue">{{ $this->stats['externals'] }} Extern</flux:badge>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Upload + External URL --}}
|
||
<flux:card class="mb-6">
|
||
<div class="flex items-start gap-4">
|
||
<div class="flex-1">
|
||
<flux:file-upload wire:model="uploads" multiple
|
||
accept="image/jpeg,image/png,image/gif,image/webp,image/svg+xml,video/mp4,video/webm,.jpg,.jpeg,.png,.gif,.webp,.svg,.mp4,.webm,.mov">
|
||
<flux:file-upload.dropzone
|
||
heading="Dateien hochladen"
|
||
text="Bilder inkl. SVG & Videos bis 200 MB - Drag & Drop oder klicken"
|
||
with-progress />
|
||
</flux:file-upload>
|
||
@if (isset($uploads) && count($uploads) > 0)
|
||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||
@foreach ($uploads as $index => $upload)
|
||
<flux:file-item
|
||
:heading="$upload->getClientOriginalName()"
|
||
:image="(str_starts_with($upload->getMimeType() ?? '', 'image/') && $upload->isPreviewable())
|
||
? $upload->temporaryUrl()
|
||
: null"
|
||
:size="$upload->getSize()" />
|
||
@endforeach
|
||
</div>
|
||
<flux:button wire:click="handleUploads" variant="primary" size="sm" class="mt-3">
|
||
{{ count($uploads) }} Datei(en) hochladen
|
||
</flux:button>
|
||
@endif
|
||
<flux:error name="uploads" />
|
||
</div>
|
||
<div class="flex flex-col gap-2 pt-2">
|
||
<flux:button wire:click="openUrlModal" icon="link" variant="ghost">
|
||
Externe URL anlegen
|
||
</flux:button>
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
|
||
{{-- Filters --}}
|
||
<div class="mb-4 flex flex-wrap items-center gap-3">
|
||
<flux:input wire:model.live.debounce.300ms="search" placeholder="Suchen..." icon="magnifying-glass" size="sm" class="w-56" />
|
||
|
||
<flux:select wire:model.live="filterType" size="sm" class="w-36">
|
||
<flux:select.option value="all">Alle Typen</flux:select.option>
|
||
<flux:select.option value="image">Bilder</flux:select.option>
|
||
<flux:select.option value="video">Videos</flux:select.option>
|
||
</flux:select>
|
||
|
||
<flux:select wire:model.live="filterSource" size="sm" class="w-36">
|
||
<flux:select.option value="all">Alle Quellen</flux:select.option>
|
||
<flux:select.option value="upload">Uploads</flux:select.option>
|
||
<flux:select.option value="external">Extern</flux:select.option>
|
||
</flux:select>
|
||
|
||
@if (! empty($this->collections))
|
||
<flux:select wire:model.live="filterCollection" size="sm" class="w-40">
|
||
<flux:select.option value="">Alle Sammlungen</flux:select.option>
|
||
@foreach ($this->collections as $col)
|
||
<flux:select.option value="{{ $col }}">{{ $col }}</flux:select.option>
|
||
@endforeach
|
||
</flux:select>
|
||
@endif
|
||
|
||
<div class="ml-auto flex items-center gap-1 rounded-lg border border-zinc-200 p-0.5 dark:border-zinc-700">
|
||
<button wire:click="$set('viewMode', 'grid')"
|
||
class="rounded-md p-1.5 transition {{ $viewMode === 'grid' ? 'bg-zinc-200 text-zinc-900 dark:bg-zinc-600 dark:text-white' : 'text-zinc-400 hover:text-zinc-600' }}">
|
||
<x-heroicon-s-squares-2x2 class="h-4 w-4" />
|
||
</button>
|
||
<button wire:click="$set('viewMode', 'list')"
|
||
class="rounded-md p-1.5 transition {{ $viewMode === 'list' ? 'bg-zinc-200 text-zinc-900 dark:bg-zinc-600 dark:text-white' : 'text-zinc-400 hover:text-zinc-600' }}">
|
||
<x-heroicon-s-list-bullet class="h-4 w-4" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Media Grid / List + Detail --}}
|
||
<div class="grid grid-cols-1 gap-6 {{ $showDetail ? 'lg:grid-cols-3' : '' }}">
|
||
<div class="{{ $showDetail ? 'lg:col-span-2' : '' }}">
|
||
@if ($viewMode === 'grid')
|
||
<div class="grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 {{ $showDetail ? 'lg:grid-cols-3' : 'lg:grid-cols-6' }}">
|
||
@forelse ($this->media as $item)
|
||
<div wire:key="dm-g-{{ $item->id }}"
|
||
class="group relative cursor-pointer overflow-hidden rounded-lg border transition-all
|
||
{{ $editingId === $item->id ? 'border-blue-500 ring-2 ring-blue-200 dark:ring-blue-800' : 'border-zinc-200 hover:border-zinc-400 dark:border-zinc-700' }}"
|
||
wire:click="startEdit({{ $item->id }})">
|
||
<div class="aspect-square bg-zinc-100 dark:bg-zinc-800">
|
||
@if ($item->isImage() && $item->isUpload())
|
||
<img src="{{ $item->getThumbnailUrl() }}"
|
||
alt="{{ $item->alt_text ?? $item->filename }}"
|
||
class="h-full w-full object-cover" loading="lazy" />
|
||
@elseif ($item->isVideo())
|
||
<div class="flex h-full w-full flex-col items-center justify-center gap-2 text-purple-400">
|
||
<x-heroicon-o-film class="h-10 w-10" />
|
||
<span class="text-xs">Video</span>
|
||
</div>
|
||
@elseif ($item->isExternal() && $item->isImage())
|
||
<div class="flex h-full w-full flex-col items-center justify-center gap-2 text-blue-400">
|
||
<x-heroicon-o-photo class="h-10 w-10" />
|
||
<span class="text-xs">Extern</span>
|
||
</div>
|
||
@else
|
||
<div class="flex h-full w-full flex-col items-center justify-center gap-2 text-zinc-400">
|
||
<x-heroicon-o-link class="h-10 w-10" />
|
||
<span class="text-xs">Link</span>
|
||
</div>
|
||
@endif
|
||
</div>
|
||
<div class="flex items-center gap-1.5 p-2">
|
||
@if ($item->isVideo())
|
||
<x-heroicon-s-film class="h-3.5 w-3.5 shrink-0 text-purple-500" />
|
||
@elseif ($item->isExternal())
|
||
<x-heroicon-s-link class="h-3.5 w-3.5 shrink-0 text-blue-500" />
|
||
@else
|
||
<x-heroicon-s-photo class="h-3.5 w-3.5 shrink-0 text-sky-500" />
|
||
@endif
|
||
<div class="min-w-0">
|
||
<p class="truncate text-xs font-medium text-zinc-700 dark:text-zinc-300">{{ $item->getDisplayName() }}</p>
|
||
<p class="text-xs text-zinc-400">{{ $item->getHumanFileSize() }}</p>
|
||
</div>
|
||
</div>
|
||
@if ($item->collection)
|
||
<div class="absolute right-1 top-1">
|
||
<flux:badge size="sm" color="blue" class="text-[10px]!">{{ $item->collection }}</flux:badge>
|
||
</div>
|
||
@endif
|
||
</div>
|
||
@empty
|
||
<div class="col-span-full py-12 text-center">
|
||
<x-heroicon-o-photo class="mx-auto mb-3 h-12 w-12 text-zinc-300" />
|
||
<flux:text>Noch keine Medien vorhanden. Laden Sie Dateien hoch oder legen Sie externe URLs an.</flux:text>
|
||
</div>
|
||
@endforelse
|
||
</div>
|
||
@else
|
||
{{-- List View --}}
|
||
<div class="overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-700">
|
||
<table class="w-full text-sm">
|
||
<thead class="border-b border-zinc-200 bg-zinc-50 text-left text-xs text-zinc-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-400">
|
||
<tr>
|
||
<th class="w-12 px-3 py-2"></th>
|
||
<th class="px-3 py-2">Name</th>
|
||
<th class="hidden px-3 py-2 sm:table-cell">Typ</th>
|
||
<th class="hidden px-3 py-2 sm:table-cell">Quelle</th>
|
||
<th class="hidden px-3 py-2 md:table-cell">Größe</th>
|
||
<th class="hidden px-3 py-2 lg:table-cell">Sammlung</th>
|
||
<th class="px-3 py-2 text-right">Datum</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="divide-y divide-zinc-100 dark:divide-zinc-800">
|
||
@forelse ($this->media as $item)
|
||
<tr wire:key="dm-l-{{ $item->id }}"
|
||
class="cursor-pointer transition {{ $editingId === $item->id ? 'bg-blue-50 dark:bg-blue-900/20' : 'hover:bg-zinc-50 dark:hover:bg-zinc-800/50' }}"
|
||
wire:click="startEdit({{ $item->id }})">
|
||
<td class="px-3 py-1.5">
|
||
<div class="flex h-8 w-8 items-center justify-center overflow-hidden rounded border border-zinc-200 bg-zinc-100 dark:border-zinc-700 dark:bg-zinc-800">
|
||
@if ($item->isImage() && $item->isUpload())
|
||
<img src="{{ $item->getThumbnailUrl() }}" class="h-full w-full object-cover" loading="lazy" />
|
||
@elseif ($item->isVideo())
|
||
<x-heroicon-s-film class="h-4 w-4 text-purple-500" />
|
||
@else
|
||
<x-heroicon-s-link class="h-4 w-4 text-blue-500" />
|
||
@endif
|
||
</div>
|
||
</td>
|
||
<td class="px-3 py-1.5">
|
||
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $item->getDisplayName() }}</span>
|
||
</td>
|
||
<td class="hidden px-3 py-1.5 sm:table-cell">
|
||
<flux:badge size="sm" :color="$item->isVideo() ? 'purple' : 'sky'">
|
||
{{ $item->isVideo() ? 'Video' : 'Bild' }}
|
||
</flux:badge>
|
||
</td>
|
||
<td class="hidden px-3 py-1.5 sm:table-cell">
|
||
<flux:badge size="sm" :color="$item->isExternal() ? 'blue' : 'zinc'">
|
||
{{ $item->isExternal() ? 'Extern' : 'Upload' }}
|
||
</flux:badge>
|
||
</td>
|
||
<td class="hidden px-3 py-1.5 text-zinc-500 md:table-cell">{{ $item->getHumanFileSize() }}</td>
|
||
<td class="hidden px-3 py-1.5 lg:table-cell">
|
||
@if ($item->collection)
|
||
<flux:badge size="sm" color="blue">{{ $item->collection }}</flux:badge>
|
||
@else
|
||
<span class="text-zinc-300">—</span>
|
||
@endif
|
||
</td>
|
||
<td class="px-3 py-1.5 text-right text-zinc-400">{{ $item->created_at->format('d.m.Y') }}</td>
|
||
</tr>
|
||
@empty
|
||
<tr>
|
||
<td colspan="7" class="py-12 text-center">
|
||
<x-heroicon-o-photo class="mx-auto mb-3 h-12 w-12 text-zinc-300" />
|
||
<flux:text>Noch keine Medien vorhanden.</flux:text>
|
||
</td>
|
||
</tr>
|
||
@endforelse
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
@endif
|
||
|
||
@if ($this->media->hasPages())
|
||
<div class="mt-4">
|
||
{{ $this->media->links() }}
|
||
</div>
|
||
@endif
|
||
</div>
|
||
|
||
{{-- Detail Sidebar --}}
|
||
@if ($showDetail && $editingId)
|
||
@php $editMedia = \App\Models\DisplayMedia::find($editingId); @endphp
|
||
@if ($editMedia)
|
||
<div class="lg:col-span-1">
|
||
<flux:card>
|
||
<div class="mb-4 flex items-center justify-between">
|
||
<flux:heading size="sm">Details</flux:heading>
|
||
<flux:button size="xs" variant="ghost" icon="x-mark" wire:click="closeDetail" />
|
||
</div>
|
||
|
||
{{-- Preview --}}
|
||
<div class="mb-4 overflow-hidden rounded-lg border border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-800">
|
||
@if ($editMedia->isImage() && $editMedia->isUpload())
|
||
<img src="{{ $editMedia->getUrl() }}" alt="{{ $editMedia->filename }}"
|
||
class="w-full object-contain" style="max-height: 300px;" />
|
||
@elseif ($editMedia->isVideo() && $editMedia->isUpload())
|
||
<video controls class="w-full" style="max-height: 300px;">
|
||
<source src="{{ $editMedia->getUrl() }}" type="{{ $editMedia->mime_type }}">
|
||
</video>
|
||
@elseif ($editMedia->isExternal())
|
||
<div class="flex flex-col items-center justify-center gap-3 py-8">
|
||
<x-heroicon-o-link class="h-12 w-12 text-blue-400" />
|
||
<span class="text-sm text-zinc-500">Externe Ressource</span>
|
||
</div>
|
||
@endif
|
||
</div>
|
||
|
||
{{-- Metadata --}}
|
||
<div class="mb-4 space-y-1 text-xs text-zinc-500 dark:text-zinc-400">
|
||
<p><strong>Datei:</strong> {{ $editMedia->filename }}</p>
|
||
<p><strong>Typ:</strong>
|
||
<flux:badge size="sm" :color="$editMedia->isVideo() ? 'purple' : 'sky'" class="inline">
|
||
{{ $editMedia->isVideo() ? 'Video' : 'Bild' }}
|
||
</flux:badge>
|
||
</p>
|
||
<p><strong>Quelle:</strong>
|
||
<flux:badge size="sm" :color="$editMedia->isExternal() ? 'blue' : 'zinc'" class="inline">
|
||
{{ $editMedia->isExternal() ? 'Extern' : 'Upload' }}
|
||
</flux:badge>
|
||
</p>
|
||
@if ($editMedia->isUpload())
|
||
<p><strong>Größe:</strong> {{ $editMedia->getHumanFileSize() }}</p>
|
||
@if ($editMedia->mime_type)
|
||
<p><strong>MIME:</strong> {{ $editMedia->mime_type }}</p>
|
||
@endif
|
||
@if ($editMedia->metadata && isset($editMedia->metadata['width']))
|
||
<p><strong>Abmessungen:</strong> {{ $editMedia->metadata['width'] }}×{{ $editMedia->metadata['height'] }} px</p>
|
||
@endif
|
||
@endif
|
||
<p><strong>Angelegt:</strong> {{ $editMedia->created_at->format('d.m.Y H:i') }}</p>
|
||
<p class="break-all"><strong>URL:</strong>
|
||
<a href="{{ $editMedia->getUrl() }}" target="_blank" class="text-blue-500 hover:underline">
|
||
{{ Str::limit($editMedia->getUrl(), 80) }}
|
||
</a>
|
||
</p>
|
||
</div>
|
||
|
||
{{-- Edit Form --}}
|
||
<div class="space-y-3">
|
||
<flux:input wire:model="editTitle" label="Titel" size="sm" placeholder="Anzeigename..." />
|
||
<flux:input wire:model="editAltText" label="Alt-Text" size="sm" placeholder="Bildbeschreibung..." />
|
||
<flux:input wire:model="editCollection" label="Sammlung" size="sm" placeholder="z.B. immobilien, moebel, brand..." />
|
||
|
||
<flux:button size="sm" variant="primary" wire:click="saveEdit" class="w-full">
|
||
Speichern
|
||
</flux:button>
|
||
</div>
|
||
|
||
<div class="mt-5 border-t border-zinc-200 pt-4 dark:border-zinc-700">
|
||
<flux:button size="sm" variant="danger" class="w-full" icon="trash"
|
||
wire:click="deleteMedia({{ $editMedia->id }})"
|
||
wire:confirm="Dieses Medium wirklich löschen?">
|
||
Löschen
|
||
</flux:button>
|
||
</div>
|
||
</flux:card>
|
||
</div>
|
||
@endif
|
||
@endif
|
||
</div>
|
||
|
||
{{-- External URL Modal --}}
|
||
<flux:modal wire:model="showUrlModal" class="max-w-lg">
|
||
<form wire:submit.prevent="saveExternalUrl">
|
||
<div class="space-y-6">
|
||
<div>
|
||
<flux:heading size="lg">Externe URL anlegen</flux:heading>
|
||
<flux:text class="mt-1">Binden Sie große Videos oder Medien von Google Drive, OneDrive oder anderen Quellen ein.</flux:text>
|
||
</div>
|
||
|
||
<div class="space-y-4">
|
||
<div>
|
||
<flux:input wire:model="urlInput" label="URL" placeholder="https://drive.google.com/file/d/..." />
|
||
<flux:error name="urlInput" />
|
||
</div>
|
||
|
||
<div class="flex items-end gap-3">
|
||
<flux:button type="button" wire:click="validateUrl" size="sm" variant="ghost" icon="arrow-path">
|
||
URL prüfen
|
||
</flux:button>
|
||
@if ($urlValidated === true)
|
||
<span class="flex items-center gap-1 text-sm text-green-600">
|
||
<x-heroicon-s-check-circle class="h-4 w-4" /> Erreichbar
|
||
</span>
|
||
@elseif ($urlValidated === false)
|
||
<span class="flex items-center gap-1 text-sm text-amber-600">
|
||
<x-heroicon-s-exclamation-triangle class="h-4 w-4" /> Nicht erreichbar – trotzdem speichern möglich
|
||
</span>
|
||
@endif
|
||
</div>
|
||
|
||
<flux:select wire:model="urlType" label="Medientyp">
|
||
<option value="video">Video</option>
|
||
<option value="image">Bild</option>
|
||
</flux:select>
|
||
|
||
<flux:input wire:model="urlTitle" label="Titel (optional)" placeholder="z.B. Showroom-Rundgang 4K" />
|
||
|
||
<flux:input wire:model="urlCollection" label="Sammlung (optional)" placeholder="z.B. immobilien, moebel..." />
|
||
</div>
|
||
|
||
<div class="flex justify-end gap-3 pt-4">
|
||
<flux:button type="button" wire:click="$set('showUrlModal', false)" variant="ghost">
|
||
Abbrechen
|
||
</flux:button>
|
||
<flux:button type="submit" variant="primary">
|
||
Anlegen
|
||
</flux:button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</flux:modal>
|
||
</div>
|