- Neues Sparkbooth-Upload-Feature: Endpoint /api/sparkbooth/upload (Token-basiert pro Galerie), Controller Api/SparkboothUploadController, Migration 2026_01_21_000001_add_upload_fields_to_galleries_table.php mit Upload-Flags/Token/Expiry;
Galerie-Modell und Factory/Seeder entsprechend erweitert.
- Filament: Neue Setup-Seite SparkboothSetup (mit View) zur schnellen Galerie- und Token-Erstellung inkl. QR/Endpoint/Snippet;
Galerie-Link-Views nutzen jetzt simple-qrcode (Composer-Dependency hinzugefügt) und bieten PNG-Download.
- Galerie-Tabelle: Slug/Pfad-Spalten entfernt, Action „Link-Details“ mit Modal; Created-at-Spalte hinzugefügt.
- Zugriffshärtung: Galerie-IDs in API (ImageController, Download/Print) geprüft; GalleryAccess/Middleware + Gallery-Modell/Slug-UUID
eingeführt; GalleryAccess-Inertia-Seite.
- UI/UX: LoadingSpinner/StyledImageDisplay verbessert, Delete-Confirm, Übersetzungen ergänzt.
78 lines
3.7 KiB
Vue
78 lines
3.7 KiB
Vue
<template>
|
|
<div class="fixed inset-0 z-[210] flex items-center justify-center bg-slate-900/80 backdrop-blur">
|
|
<div class="w-full max-w-4xl overflow-hidden rounded-3xl border border-white/10 bg-white/95 shadow-2xl ring-1 ring-black/10 dark:bg-slate-900/95">
|
|
<div class="flex flex-col gap-6 p-6 sm:p-8">
|
|
<div class="flex items-start justify-between gap-4">
|
|
<div>
|
|
<p class="text-xs uppercase tracking-[0.35em] text-slate-500 dark:text-slate-400">Ergebnis</p>
|
|
<h2 class="text-2xl font-semibold text-slate-900 dark:text-white">{{ __('api.styled_image_display.title') }}</h2>
|
|
<p class="text-sm text-slate-500 dark:text-slate-300">{{ __('api.styled_image_display.keep_hint') }}</p>
|
|
</div>
|
|
<button
|
|
type="button"
|
|
class="rounded-full border border-white/20 bg-white/10 p-2 text-slate-900 shadow-sm transition hover:border-slate-300 hover:text-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-slate-300 dark:text-white"
|
|
@click="$emit('close')"
|
|
aria-label="Schließen"
|
|
>
|
|
<font-awesome-icon :icon="['fas', 'xmark']" class="h-5 w-5" />
|
|
</button>
|
|
</div>
|
|
|
|
<div class="overflow-hidden rounded-2xl border border-slate-200/60 bg-slate-50 dark:border-white/10 dark:bg-white/5">
|
|
<img :src="image.path" alt="Styled Image" class="mx-auto max-h-[60vh] w-full object-contain" />
|
|
</div>
|
|
|
|
<div class="flex flex-wrap items-center justify-end gap-3">
|
|
<button
|
|
type="button"
|
|
class="rounded-2xl border border-slate-200 bg-white px-5 py-2.5 text-sm font-semibold text-slate-800 shadow-sm transition hover:border-emerald-300 hover:text-emerald-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-300 dark:border-white/20 dark:bg-white/10 dark:text-white"
|
|
@click="$emit('keep', image)"
|
|
>
|
|
{{ __('api.styled_image_display.keep_button') }}
|
|
</button>
|
|
<button
|
|
v-if="!confirmingDelete"
|
|
type="button"
|
|
class="rounded-2xl border border-rose-200 bg-rose-50 px-5 py-2.5 text-sm font-semibold text-rose-700 shadow-sm transition hover:border-rose-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-rose-300 dark:border-rose-500/30 dark:bg-rose-500/10 dark:text-rose-100"
|
|
@click="confirmingDelete = true"
|
|
>
|
|
{{ __('api.styled_image_display.delete_button') }}
|
|
</button>
|
|
<div v-else class="flex items-center gap-2 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-2.5 text-sm text-rose-700 shadow-sm dark:border-rose-500/30 dark:bg-rose-500/10 dark:text-rose-100">
|
|
<span>{{ __('api.styled_image_display.delete_confirm') }}</span>
|
|
<button
|
|
type="button"
|
|
class="rounded-lg bg-rose-600 px-3 py-1 text-white shadow-sm transition hover:bg-rose-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/80"
|
|
@click="$emit('delete', image)"
|
|
>
|
|
{{ __('api.styled_image_display.delete_button') }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="rounded-lg border border-slate-200 px-3 py-1 text-slate-700 transition hover:border-slate-300 dark:border-white/20 dark:text-white"
|
|
@click="confirmingDelete = false"
|
|
>
|
|
{{ __('settings.cancel_button') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue';
|
|
|
|
defineProps({
|
|
image: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
defineEmits(['keep', 'delete', 'close']);
|
|
|
|
const confirmingDelete = ref(false);
|
|
</script>
|