Display Module 13-05-2026

This commit is contained in:
Kevin Adametz 2026-05-13 14:34:08 +02:00
parent 6a65354f4c
commit 9262132325
41 changed files with 496 additions and 334 deletions

View file

@ -183,7 +183,7 @@
<flux:navlist.group :heading="__('Cabinet')" class="grid mb-4">
<flux:navlist.group expandable
:expanded="request()->routeIs(['admin.cms.display-dashboard', 'admin.cms.display-media', 'admin.cms.display-modules', 'admin.cms.display-module-edit', 'admin.cms.display-versions', 'admin.cms.display-version-edit', 'admin.cms.displays', 'admin.cms.cabinet', 'admin.cms.cabinet-tablet'])"
:expanded="request()->routeIs(['admin.cms.display-dashboard', 'admin.cms.display-media', 'admin.cms.display-modules', 'admin.cms.display-module-edit', 'admin.cms.displays', 'admin.cms.cabinet', 'admin.cms.cabinet-tablet'])"
heading="Store Displays" class="grid">
<flux:navlist.item icon="squares-2x2" :href="route('admin.cms.display-dashboard')"
:current="request()->routeIs('admin.cms.display-dashboard')" wire:navigate>{{ __('Übersicht') }}
@ -192,7 +192,7 @@
:current="request()->routeIs('admin.cms.display-media')" wire:navigate>{{ __('Mediathek') }}
</flux:navlist.item>
<flux:navlist.item icon="rectangle-group" :href="route('admin.cms.display-modules')"
:current="request()->routeIs(['admin.cms.display-modules', 'admin.cms.display-module-edit', 'admin.cms.display-versions', 'admin.cms.display-version-edit'])" wire:navigate>{{ __('Module') }}
:current="request()->routeIs(['admin.cms.display-modules', 'admin.cms.display-module-edit'])" wire:navigate>{{ __('Module') }}
</flux:navlist.item>
<flux:navlist.item icon="tv" :href="route('admin.cms.displays')"
:current="request()->routeIs('admin.cms.displays')" wire:navigate>{{ __('Displays') }}

View file

@ -171,9 +171,9 @@ $tabletStatus = computed(function () {
Es besteht aus drei Bereichen, die Sie über die Kacheln oben erreichen:
</p>
<ul class="mt-2 ml-5 list-disc space-y-1">
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Mediathek</strong> - Zentrale Verwaltung aller Bilder und Videos fuer die Displays. Dateien bis 200 MB direkt hochladen oder groessere Videos als externe URL (Google Drive, OneDrive) einbinden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Module</strong> Wiederverwendbare Content-Pakete, die auf den Displays abgespielt werden. Jede Modul hat einen bestimmten Typ und enthält passende Inhalte (Videos, Bilder oder Angebots-Slides).</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Displays</strong> Die physischen Bildschirme im Showroom. Jedem Display werden eine oder mehrere Module als Playlist zugewiesen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Mediathek</strong> - Zentrale Verwaltung aller Bilder, SVG-Logos und Videos fuer die Displays. Dateien bis 200 MB direkt hochladen oder groessere Videos als externe URL (Google Drive, OneDrive) einbinden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Module</strong> Wiederverwendbare Content-Pakete, die auf den Displays abgespielt werden. Jedes Modul hat einen bestimmten Typ, passende Inhalte und eigene Meta-Einstellungen fuer Logo, Claim, Footer, QR-Code oder Theme.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Displays</strong> Die physischen Bildschirme im Showroom. Pro Display gibt es einen Live-Stand und optional einen Entwurf, der separat vorbereitet, getestet und bewusst veröffentlicht wird.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Info-Tablet</strong> Das Tablet an der Eingangstür des Showrooms. Hier verwalten Sie Öffnungszeiten, den aktuellen Store-Status und Hinweise für Besucher.</li>
</ul>
</div>
@ -190,10 +190,10 @@ $tabletStatus = computed(function () {
Sie ist unabhängig von der Website-Mediathek (Flux CMS) und speziell auf die Anforderungen der Displays zugeschnitten.
</p>
<ul class="mt-2 ml-5 list-disc space-y-1">
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Direkt-Upload:</strong> Bilder und Videos bis 200 MB direkt per Drag-and-drop oder Dateiauswahl hochladen. Die Dateien werden auf dem Server gespeichert und stehen sofort zur Verfügung.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Direkt-Upload:</strong> Bilder, SVG-Dateien und Videos bis 200 MB direkt per Drag-and-drop oder Dateiauswahl hochladen. Die Dateien werden auf dem Server gespeichert und stehen sofort zur Verfügung.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Externe URLs:</strong> Für Videos über 200 MB (z.&nbsp;B. 4K-Showroom-Rundgänge) können Sie einen Freigabe-Link von Google Drive, OneDrive oder anderen Cloud-Diensten hinterlegen. Diese URL wird wie ein normales Medium in der Mediathek verwaltet und kann genauso in Module eingebunden werden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Sammlungen:</strong> Ordnen Sie Medien in Sammlungen wie <em>immobilien</em>, <em>moebel</em> oder <em>brand</em>, um bei vielen Dateien den Überblick zu behalten.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Medienauswahl im Editor:</strong> Beim Bearbeiten eines Moduls erscheint ein „Aus Mediathek"-Button. Darüber öffnen Sie die Medienauswahl und können bestehende Medien wählen oder direkt neue hochladen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Medienauswahl im Editor:</strong> Beim Bearbeiten eines Moduls erscheint ein „Aus Mediathek"-Button. Darüber öffnen Sie die Medienauswahl und können bestehende Medien wählen oder direkt neue Dateien inklusive SVG-Logos hochladen.</li>
</ul>
</div>
@ -211,19 +211,19 @@ $tabletStatus = computed(function () {
<ul class="mt-2 ml-5 list-disc space-y-1">
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">Video-Display</strong>
Für Video-Playlists mit optionalem Footer. Inhalte: <em>Videos</em> (Dateiname, Titel, Position/Ausschnitt) und <em>Footer-Zeilen</em> (Überschrift, Unterzeile, optionaler QR-Code-Link).
Für Video-Playlists mit optionalem Footer. Inhalte: <em>Videos</em> aus der Mediathek oder Legacy-Dateinamen, Position/Ausschnitt und <em>Footer-Zeilen</em> (Überschrift, Unterzeile, optionaler QR-Code-Link). Mediathek-URLs wie <code class="text-xs bg-zinc-100 dark:bg-zinc-800 px-1 py-0.5 rounded">/storage/...</code> werden direkt abgespielt.
</li>
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">B2in Display</strong>
Für Medien-Rotation (Bilder und Videos) im Marken-Design. Inhalte: <em>Media-Items</em> mit Kategorie (Immobilien / Möbel), Überschrift, Unterzeile und Anzeigedauer. Unterstützt Light-/Dark-Theme.
Für Medien-Rotation (Bilder und Videos) im Marken-Design. Inhalte: <em>Media-Items</em> mit Kategorie (Immobilien / Möbel), Überschrift, Unterzeile und Anzeigedauer. Unterstützt Light-/Dark-Theme sowie zentrale Meta-Einstellungen für Header-Logo, Claim, Footer-Domain und QR-Code.
</li>
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">Angebote</strong>
Für Produkt-Slides im Angebotsformat. Verschiedene Slide-Layouts: Intro, Produkt-Hero, Produkt-Details und Impuls-Slides mit Preisen, Badges und QR-Codes.
Für Produkt-Slides im Angebotsformat. Verschiedene Slide-Layouts: Intro, Produkt-Hero, Produkt-Details und Impuls-Slides mit Preisen, Badges und QR-Codes. Logo, Brand-Text, Footer-Claim und Web-/QR-URL werden einmal am Modul gepflegt und automatisch von allen Slides übernommen.
</li>
</ul>
<p class="mt-2">
Innerhalb eines Moduls können Sie beliebig viele Inhalte anlegen, die Reihenfolge per Hoch/Runter-Sortierung festlegen und einzelne Einträge aktivieren oder deaktivieren.
Innerhalb eines Moduls können Sie beliebig viele Inhalte anlegen, die Reihenfolge per Hoch/Runter-Sortierung festlegen und einzelne Einträge aktivieren oder deaktivieren. Der Modul-Editor zeigt Inline-Vorschaubilder, eine 9:16-Player-Vorschau und eine Vollbild-Vorschau. Im Slide-Bearbeiten-Dialog wird nur der aktuell bearbeitete Slide als Einzel-Vorschau gerendert.
</p>
</div>
@ -238,9 +238,11 @@ $tabletStatus = computed(function () {
Ein <strong class="font-medium text-zinc-800 dark:text-zinc-200">Display</strong> repräsentiert einen physischen Bildschirm im Showroom.
</p>
<ul class="mt-2 ml-5 list-disc space-y-1">
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Modul-Zuweisung:</strong> Jedem Display können Sie eine oder mehrere Module zuordnen. Die Module werden in der festgelegten Reihenfolge als Playlist abgespielt.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Live und Entwurf:</strong> Jedes Display zeigt den veröffentlichten Live-Stand und optional einen Entwurf. Entwürfe können aus Live angelegt, separat bearbeitet, verworfen oder veröffentlicht werden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Modul-Zuweisung:</strong> Jedem Live- oder Entwurfsstand können Sie eine oder mehrere Module zuordnen. Die Module werden in der festgelegten Reihenfolge als Playlist abgespielt.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Vorschau:</strong> Live- und Entwurfs-URLs sind direkt kopierbar. Entwürfe und Module können zusätzlich im 9:16-Iframe oder im Vollbild geprüft werden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Aktiv/Inaktiv:</strong> Über den Aktiv-Status können Sie einzelne Displays vorübergehend deaktivieren, ohne die Konfiguration zu verlieren.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">API-Anbindung:</strong> Jedes Display ruft seine Inhalte über eine JSON-API ab (<code class="text-xs bg-zinc-100 dark:bg-zinc-800 px-1 py-0.5 rounded">/api/display/{id}/config</code>). Änderungen werden beim nächsten Abruf automatisch übernommen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">API-Anbindung:</strong> Jedes Display ruft seine Live-Inhalte über eine JSON-API ab (<code class="text-xs bg-zinc-100 dark:bg-zinc-800 px-1 py-0.5 rounded">/api/display/{id}/config</code>). Entwürfe laufen über Preview-Tokens, Module über eigene Preview-Endpunkte.</li>
</ul>
</div>
@ -282,10 +284,12 @@ $tabletStatus = computed(function () {
Typischer Workflow
</flux:heading>
<ol class="mt-2 ml-5 list-decimal space-y-1">
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Medien hochladen</strong> Bilder, SVG-Logos oder Videos in der Display-Mediathek ablegen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Modul erstellen</strong> Unter „Module" ein neues Modul mit passendem Typ anlegen (z.&nbsp;B. „Frühling 2026 Video").</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Inhalte hinzufügen</strong> Im Modul Videos, Medien oder Slides anlegen, Reihenfolge festlegen und aktivieren.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Display zuweisen</strong> Unter „Displays" das Modul einem physischen Bildschirm zuordnen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Fertig</strong> Das Display lädt die neuen Inhalte automatisch über die API.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Meta-Einstellungen pflegen</strong> Logo, Claim, Footer, QR-Code, Theme oder Anzeigezeiten einmal auf Modulebene setzen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Inhalte hinzufügen</strong> Im Modul Videos, Medien oder Slides anlegen, Reihenfolge festlegen, aktivieren und per Vorschau prüfen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Display-Entwurf erstellen</strong> Unter „Displays" aus dem Live-Stand einen Entwurf erzeugen und dort Module hinzufügen, sortieren oder entfernen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Prüfen und veröffentlichen</strong> Entwurf in der 9:16-Vorschau oder im Vollbild testen und anschließend bewusst veröffentlichen.</li>
</ol>
</div>

View file

@ -10,6 +10,29 @@
</x-success-alert>
@endif
@php
$displayPlayerUrl = rtrim(config('display.player_url') ?: 'https://cabinet.b2in.eu/display', '/');
$displayOverviewUrl = $displayPlayerUrl.'/';
@endphp
<flux:card class="mb-6 border-blue-200 bg-blue-50/70 dark:border-blue-500/30 dark:bg-blue-950/20">
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
<div>
<flux:heading size="lg">{{ __('Öffentliche Display-Übersicht') }}</flux:heading>
<flux:text class="mt-1">
{{ __('Hier sehen Sie alle aktiven Live-Displays und können die Wiedergabe direkt öffnen.') }}
</flux:text>
<div class="mt-2 text-xs font-mono text-blue-700 dark:text-blue-300">
{{ $displayOverviewUrl }}
</div>
</div>
<flux:button href="{{ $displayOverviewUrl }}" target="_blank" variant="primary" icon="arrow-top-right-on-square">
{{ __('Display-Übersicht öffnen') }}
</flux:button>
</div>
</flux:card>
<flux:card>
<div class="flex items-center justify-between mb-6">
<div>
@ -30,7 +53,7 @@
<div class="space-y-4">
@foreach($displays as $display)
@php
$liveDisplayUrl = url('/_cabinet/display/index.html').'?id='.$display->id;
$liveDisplayUrl = $displayPlayerUrl.'/?id='.$display->id;
$liveApiUrl = url('/api/display/'.$display->id.'/config');
@endphp
<div wire:key="display-{{ $display->id }}"
@ -364,6 +387,7 @@
wire:key="draft-preview-{{ $previewFrameRefreshCounter }}"
src="{{ $draftPreviewUrl }}"
class="h-full w-full border-0"
loading="lazy"
title="{{ __('Entwurfs-Vorschau') }}"
></iframe>
@else

View file

@ -70,6 +70,7 @@
wire:key="module-preview-{{ $previewFrameRefreshCounter }}"
src="{{ $this->modulePreviewUrl() }}"
class="h-full w-full border-0"
loading="lazy"
title="{{ __('Modul-Vorschau') }}"
></iframe>
</div>
@ -250,6 +251,7 @@
wire:key="item-modal-module-preview-{{ $previewFrameRefreshCounter }}"
src="{{ $this->itemPreviewUrl() }}"
class="h-full w-full border-0"
loading="lazy"
title="{{ __('Einzel-Vorschau im Bearbeiten-Dialog') }}"
></iframe>
</div>

View file

@ -3,7 +3,7 @@
accept="image/jpeg,image/png,image/gif,image/webp,image/svg+xml,.pdf,.doc,.docx,.jpg,.jpeg,.png">
<flux:file-upload.dropzone
heading="Dateien hochladen"
text="Bilder (JPG, PNG, WebP, SVG) und Dokumente (PDF, DOC) — max. 10 MB pro Datei"
text="Bilder (JPG, PNG, WebP, SVG) und Dokumente (PDF, DOC) — max. 200 MB pro Datei"
with-progress />
</flux:file-upload>

View file

@ -47,8 +47,15 @@
</flux:badge>
<span class="font-semibold text-sm">{{ $item->content['title'] ?? $item->content['filename'] ?? '' }}</span>
</div>
<div class="text-xs text-zinc-600 dark:text-zinc-400 space-x-4">
<span>{{ $item->content['filename'] ?? '' }}</span>
@php
$videoSource = $item->content['filename'] ?? '';
$isMediaLibrarySource = str_starts_with($videoSource, '/storage/') || str_starts_with($videoSource, 'http');
@endphp
<div class="flex flex-wrap items-center gap-2 text-xs text-zinc-600 dark:text-zinc-400">
<flux:badge size="sm" :color="$isMediaLibrarySource ? 'sky' : 'zinc'">
{{ $isMediaLibrarySource ? __('Mediathek') : __('Legacy-Datei') }}
</flux:badge>
<span class="truncate">{{ $videoSource ?: '' }}</span>
<span>Position: {{ $item->content['position'] ?? 25 }}%</span>
</div>
</div>

View file

@ -272,16 +272,16 @@ new class extends Component
$rules['deliveryRadius'] = 'required|integer|min:1|max:500';
$rules['assemblyRadius'] = 'required|integer|min:1|max:500';
$rules['newTeamPhotos'] = 'nullable|array|max:10';
$rules['newTeamPhotos.*'] = 'image|mimes:jpeg,jpg,png|max:10240';
$rules['newTeamPhotos.*'] = 'image|mimes:jpeg,jpg,png|max:204800';
$rules['newShowroomPhotos'] = 'nullable|array|max:20';
$rules['newShowroomPhotos.*'] = 'image|mimes:jpeg,jpg,png|max:10240';
$rules['newShowroomPhotos.*'] = 'image|mimes:jpeg,jpg,png|max:204800';
}
if ($this->isManufacturer()) {
$rules['brandName'] = 'required|string|max:255';
$rules['brandDescription'] = 'nullable|string|max:1000';
$rules['newBrandImages'] = 'nullable|array|max:10';
$rules['newBrandImages.*'] = 'image|mimes:jpeg,jpg,png|max:10240';
$rules['newBrandImages.*'] = 'image|mimes:jpeg,jpg,png|max:204800';
}
$this->validate($rules, [
@ -305,11 +305,11 @@ new class extends Component
'foundedYear.min' => __('Das Gründungsjahr muss nach 1800 liegen.'),
'foundedYear.max' => __('Das Gründungsjahr darf nicht in der Zukunft liegen.'),
'newTeamPhotos.*.image' => __('Nur Bilder (JPG, PNG) erlaubt.'),
'newTeamPhotos.*.max' => __('Bilder dürfen maximal 10 MB groß sein.'),
'newTeamPhotos.*.max' => __('Bilder dürfen maximal 200 MB groß sein.'),
'newShowroomPhotos.*.image' => __('Nur Bilder (JPG, PNG) erlaubt.'),
'newShowroomPhotos.*.max' => __('Bilder dürfen maximal 10 MB groß sein.'),
'newShowroomPhotos.*.max' => __('Bilder dürfen maximal 200 MB groß sein.'),
'newBrandImages.*.image' => __('Nur Bilder (JPG, PNG) erlaubt.'),
'newBrandImages.*.max' => __('Bilder dürfen maximal 10 MB groß sein.'),
'newBrandImages.*.max' => __('Bilder dürfen maximal 200 MB groß sein.'),
]);
$specialties = array_values(array_filter(
@ -793,7 +793,7 @@ new class extends Component
<flux:card class="shadow-elegant">
<div class="mb-4">
<flux:heading size="lg">{{ __('Team-Fotos') }}</flux:heading>
<flux:subheading>{{ __('Nur JPG/PNG max. 10 MB pro Bild') }}</flux:subheading>
<flux:subheading>{{ __('Nur JPG/PNG max. 200 MB pro Bild') }}</flux:subheading>
</div>
<flux:separator class="mb-6" />
@ -867,7 +867,7 @@ new class extends Component
@endif
<flux:file-upload wire:model="newTeamPhotos" multiple accept="image/jpeg,image/png,.jpg,.jpeg,.png">
<flux:file-upload.dropzone heading="{{ __('Team-Fotos hochladen') }}" text="{{ __('JPEG oder PNG max. 10 MB') }}" with-progress />
<flux:file-upload.dropzone heading="{{ __('Team-Fotos hochladen') }}" text="{{ __('JPEG oder PNG max. 200 MB') }}" with-progress />
</flux:file-upload>
@if (count($newTeamPhotos) > 0)
@ -892,7 +892,7 @@ new class extends Component
<flux:card class="shadow-elegant">
<div class="mb-4">
<flux:heading size="lg">{{ __('Showroom-Galerie') }}</flux:heading>
<flux:subheading>{{ __('Bilder Ihres Showrooms für das öffentliche Profil nur JPG/PNG, max. 10 MB') }}</flux:subheading>
<flux:subheading>{{ __('Bilder Ihres Showrooms für das öffentliche Profil nur JPG/PNG, max. 200 MB') }}</flux:subheading>
</div>
<flux:separator class="mb-6" />
@ -966,7 +966,7 @@ new class extends Component
@endif
<flux:file-upload wire:model="newShowroomPhotos" multiple accept="image/jpeg,image/png,.jpg,.jpeg,.png">
<flux:file-upload.dropzone heading="{{ __('Showroom-Bilder hochladen') }}" text="{{ __('JPEG oder PNG max. 10 MB') }}" with-progress />
<flux:file-upload.dropzone heading="{{ __('Showroom-Bilder hochladen') }}" text="{{ __('JPEG oder PNG max. 200 MB') }}" with-progress />
</flux:file-upload>
@if (count($newShowroomPhotos) > 0)
@ -993,7 +993,7 @@ new class extends Component
<flux:card class="shadow-elegant">
<div class="mb-4">
<flux:heading size="lg">{{ __('Marken-Bilder') }}</flux:heading>
<flux:subheading>{{ __('Bilder für Ihre Marken-Präsentation (Atmosphäre, Brand-Story etc.) nur JPG/PNG, max. 10 MB') }}</flux:subheading>
<flux:subheading>{{ __('Bilder für Ihre Marken-Präsentation (Atmosphäre, Brand-Story etc.) nur JPG/PNG, max. 200 MB') }}</flux:subheading>
</div>
<flux:separator class="mb-6" />
@ -1067,7 +1067,7 @@ new class extends Component
@endif
<flux:file-upload wire:model="newBrandImages" multiple accept="image/jpeg,image/png,.jpg,.jpeg,.png">
<flux:file-upload.dropzone heading="{{ __('Marken-Bilder hochladen') }}" text="{{ __('JPEG oder PNG max. 10 MB') }}" with-progress />
<flux:file-upload.dropzone heading="{{ __('Marken-Bilder hochladen') }}" text="{{ __('JPEG oder PNG max. 200 MB') }}" with-progress />
</flux:file-upload>
@if (count($newBrandImages) > 0)

View file

@ -461,7 +461,7 @@ new class extends Component
'status' => 'required|in:active,draft',
// Bilder
'mainImages' => 'nullable|array|min:0|max:10',
'mainImages.*' => 'mimes:jpeg,jpg,png|max:10240',
'mainImages.*' => 'mimes:jpeg,jpg,png|max:204800',
// Maße & Material
'widthCm' => 'nullable|integer|min:1',
'heightCm' => 'nullable|integer|min:1',
@ -546,7 +546,7 @@ new class extends Component
'priceDisplayText.required_if' => __('Bei Ab-Preis ist eine Preisangabe erforderlich (z.B. "Ab 2.500 €").'),
'mainImages.max' => __('Maximal 10 Produktbilder erlaubt.'),
'mainImages.*.mimes' => __('Nur Bilder (JPG, JPEG, PNG) erlaubt.'),
'mainImages.*.max' => __('Bilder dürfen maximal 10 MB groß sein.'),
'mainImages.*.max' => __('Bilder dürfen maximal 200 MB groß sein.'),
'sku.unique' => __('Diese Artikelnummer ist bereits vergeben.'),
'sellingPrice.min' => __('Der Verkaufspreis muss größer als 0 sein.'),
'countryOfOrigin.size' => __('Bitte geben Sie einen gültigen 2-stelligen ISO-Ländercode ein (z.B. DE).'),
@ -1229,7 +1229,7 @@ new class extends Component
<flux:card class="shadow-elegant">
<div class="mb-4">
<flux:heading size="lg">{{ __('Produktbilder') }}</flux:heading>
<flux:subheading>{{ __('Nur Bilder (JPG, JPEG, PNG) max. 10 MB pro Bild, max. 10 Bilder') }}
<flux:subheading>{{ __('Nur Bilder (JPG, JPEG, PNG) max. 200 MB pro Bild, max. 10 Bilder') }}
</flux:subheading>
</div>
<flux:separator class="mb-6" />
@ -1309,7 +1309,7 @@ new class extends Component
<flux:file-upload wire:model="mainImages" label="Upload files" multiple
accept="image/jpeg,image/png,.jpg,.jpeg,.png">
<flux:file-upload.dropzone heading="{{ __('Bilder hochladen') }}"
text="{{ __('Nur JPEG oder PNG max. 10 MB') }}" with-progress />
text="{{ __('Nur JPEG oder PNG max. 200 MB') }}" with-progress />
</flux:file-upload>
@if (isset($mainImages) && count($mainImages) > 0)

View file

@ -238,7 +238,7 @@ new class extends Component
'status' => 'required|in:active,draft',
'partnerProductNumber' => 'nullable|string|max:100',
'mainImages' => 'nullable|array|min:0|max:10',
'mainImages.*' => 'mimes:jpeg,jpg,png|max:10240',
'mainImages.*' => 'mimes:jpeg,jpg,png|max:204800',
];
$messages = [
@ -250,7 +250,7 @@ new class extends Component
'categoryId.required' => __('Bitte wählen Sie eine Kategorie aus.'),
'mainImages.max' => __('Maximal 10 Produktbilder erlaubt.'),
'mainImages.*.mimes' => __('Nur Bilder (JPG, JPEG, PNG) erlaubt.'),
'mainImages.*.max' => __('Bilder dürfen maximal 10 MB groß sein.'),
'mainImages.*.max' => __('Bilder dürfen maximal 200 MB groß sein.'),
];
if ($isAdminWithoutPartner) {
@ -459,7 +459,7 @@ new class extends Component
<flux:card class="shadow-elegant">
<div class="mb-4">
<flux:heading size="lg">{{ $isEditing ? __('Produktbilder') : __('Produktbild') }}</flux:heading>
<flux:subheading>{{ __('Nur Bilder (JPG, JPEG, PNG) max. 10 MB pro Bild, max. 10 Bilder') }}
<flux:subheading>{{ __('Nur Bilder (JPG, JPEG, PNG) max. 200 MB pro Bild, max. 10 Bilder') }}
</flux:subheading>
</div>
<flux:separator class="mb-6" />
@ -539,7 +539,7 @@ new class extends Component
<flux:file-upload wire:model="mainImages" label="Upload files" multiple
accept="image/jpeg,image/png,.jpg,.jpeg,.png">
<flux:file-upload.dropzone heading="{{ __('Bilder hochladen') }}"
text="{{ __('Nur JPEG oder PNG max. 10 MB') }}" with-progress />
text="{{ __('Nur JPEG oder PNG max. 200 MB') }}" with-progress />
</flux:file-upload>
@if (isset($mainImages) && count($mainImages) > 0)