finished the upgrade to filament 4. completely revamped the frontend with codex, now it looks great!
This commit is contained in:
@@ -1,135 +1,181 @@
|
||||
<template>
|
||||
<div class="context-menu-overlay" @click.self="$emit('close')">
|
||||
<div class="context-menu" :style="{ top: `${position.y}px`, left: `${position.x}px` }">
|
||||
<div class="context-menu-image-preview">
|
||||
<img :src="image.path" :alt="'Selected Image ' + image.name" />
|
||||
</div>
|
||||
<div class="context-menu-options">
|
||||
<div v-if="!showStyleSelectorView" class="flex flex-col p-2 space-y-2">
|
||||
<button @click="$emit('close')" class="context-menu-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-10 h-10 inline-block align-middle mr-2">
|
||||
<path fill-rule="evenodd" d="M5.47 5.47a.75.75 0 0 1 1.06 0L12 10.94l5.47-5.47a.75.75 0 1 1 1.06 1.06L13.06 12l5.47 5.47a.75.75 0 1 1-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 0 1-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
|
||||
<path d="M6.22 6.22a.75.75 0 0 1 1.06 0L12 10.94l4.72-4.72a.75.75 0 1 1 1.06 1.06L13.06 12l4.72 4.72a.75.75 0 1 1-1.06 1.06L12 13.06l-4.72 4.72a.75.75 0 0 1-1.06-1.06L10.94 12 6.22 7.28a.75.75 0 0 1 0-1.06Z" />
|
||||
</svg>
|
||||
Schließen
|
||||
</button>
|
||||
<button v-if="settings.show_print_button === '1'" @click="$emit('print', image)" class="context-menu-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" class="w-8 h-8 inline-block align-middle mr-2"><!--!Font Awesome Free v6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M128 0C92.7 0 64 28.7 64 64l0 96 64 0 0-96 226.7 0L384 93.3l0 66.7 64 0 0-66.7c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0L128 0zM384 352l0 32 0 64-256 0 0-64 0-16 0-16 256 0zm64 32l32 0c17.7 0 32-14.3 32-32l0-96c0-35.3-28.7-64-64-64L64 192c-35.3 0-64 28.7-64 64l0 96c0 17.7 14.3 32 32 32l32 0 0 64c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-64zM432 248a24 24 0 1 1 0 48 24 24 0 1 1 0-48z"/></svg>
|
||||
Drucken
|
||||
</button>
|
||||
<button @click="showStyleSelectorView = true" class="context-menu-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" class="w-8 h-8 inline-block align-middle mr-2"><!--!Font Awesome Pro v6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2025 Fonticons, Inc.--><path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM183.2 132.6c-1.3-2.8-4.1-4.6-7.2-4.6s-5.9 1.8-7.2 4.6l-16.6 34.7-38.1 5c-3.1 .4-5.6 2.5-6.6 5.5s-.1 6.2 2.1 8.3l27.9 26.5-7 37.8c-.6 3 .7 6.1 3.2 7.9s5.8 2 8.5 .6L176 240.5l33.8 18.3c2.7 1.5 6 1.3 8.5-.6s3.7-4.9 3.2-7.9l-7-37.8L242.4 186c2.2-2.1 3.1-5.3 2.1-8.3s-3.5-5.1-6.6-5.5l-38.1-5-16.6-34.7zm160 0c-1.3-2.8-4.1-4.6-7.2-4.6s-5.9 1.8-7.2 4.6l-16.6 34.7-38.1 5c-3.1 .4-5.6 2.5-6.6 5.5s-.1 6.2 2.1 8.3l27.9 26.5-7 37.8c-.6 3 .7 6.1 3.2 7.9s5.8 2 8.5 .6L336 240.5l33.8 18.3c2.7 1.5 6 1.3 8.5-.6s3.7-4.9 3.2-7.9l-7-37.8L402.4 186c2.2-2.1 3.1-5.3 2.1-8.3s-3.5-5.1-6.6-5.5l-38.1-5-16.6-34.7zm6.3 175.8c-28.9 6.8-60.5 10.5-93.6 10.5s-64.7-3.7-93.6-10.5c-18.7-4.4-35.9 12-25.5 28.1c24.6 38.1 68.7 63.5 119.1 63.5s94.5-25.4 119.1-63.5c10.4-16.1-6.8-32.5-25.5-28.1z"/></svg>
|
||||
Stil ändern
|
||||
</button>
|
||||
<button v-if="isNonLocalAccess()" @click="$emit('download', image)" class="context-menu-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" class="w-8 h-8 inline-block align-middle mr-2"><!--!Font Awesome Free v6.7.2 by @fontawesome - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32V240c0 8.8-7.2 16-16 16s-16-7.2-16-16V64.7c0-5.4-1.2-10.7-3.2-15.7l-8.4-8.4c-2.3-2.3-2.3-6.1 0-8.5s6.1-2.3 8.5 0l8.4 8.4c5.3 5.3 11.4 8.6 18.2 9.7L338.6 59.2c11.4 1.9 23.5 2.9 35.4 2.9s24-1 35.4-2.9l48.6-9.1c6.8-1.1 12.9-4.4 18.2-9.7l8.4-8.4c2.3-2.3 6.1-2.3 8.5 0s2.3 6.1 0 8.5l-8.4 8.4c-2 5-3.2 10.3-3.2 15.7V240c0 8.8-7.2 16-16 16s-16-7.2-16-16V32zm-32 264.3c-43.7-5.5-79.7-30.9-90.7-69.7H128c-5.4 0-9.8-4.4-9.8-9.8s4.4-9.8 9.8-9.8h128c8.8 0 16 7.2 16 16s-7.2 16-16 16H133.3c18.1 30.9 55.4 56.9 100.7 56.9s82.6-26 100.7-56.9H384c8.8 0 16 7.2 16 16s-7.2 16-16 16H128c-5.4 0-9.8-4.4-9.8-9.8s4.4-9.8 9.8-9.8h136.3c-11 38.8-47 64.2-90.7 69.7z"/></svg>
|
||||
Herunterladen
|
||||
</button>
|
||||
<div class="fixed inset-0 z-[110] flex items-center justify-center bg-slate-950/80 px-4 backdrop-blur-lg" @click.self="$emit('close')">
|
||||
<div class="w-full max-w-6xl overflow-hidden rounded-[2.5rem] border border-white/10 bg-white/95 text-slate-900 shadow-[0_45px_85px_rgba(15,23,42,0.45)] ring-1 ring-slate-200 transition dark:bg-slate-900/95 dark:text-white">
|
||||
<div class="flex flex-col gap-6 lg:flex-row">
|
||||
<figure class="relative flex-1 overflow-hidden bg-slate-900/80">
|
||||
<img
|
||||
v-if="image?.path"
|
||||
:src="image.path"
|
||||
:alt="imageLabel"
|
||||
class="h-full w-full object-contain"
|
||||
/>
|
||||
<div v-else class="flex h-full min-h-[320px] items-center justify-center text-slate-500">
|
||||
Kein Bild geladen
|
||||
</div>
|
||||
<div class="pointer-events-none absolute inset-x-0 top-0 flex items-center justify-between p-6 text-xs uppercase tracking-[0.4em] text-white/70">
|
||||
<span>{{ image?.name || 'Ausgewähltes Bild' }}</span>
|
||||
<span>{{ image?.id }}</span>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<div class="flex w-full flex-col gap-6 p-6 lg:w-[360px]">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs uppercase tracking-[0.4em] text-slate-400">Menü</p>
|
||||
<h2 class="mt-1 text-2xl font-semibold leading-tight">{{ imageLabel }}</h2>
|
||||
<p class="text-sm text-slate-500 dark:text-slate-400 truncate">
|
||||
{{ image?.path }}
|
||||
</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-rose-400 hover:text-rose-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-rose-400 dark:text-white"
|
||||
@click="$emit('close')"
|
||||
aria-label="Kontextmenü schließen"
|
||||
>
|
||||
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m6 6 12 12M6 18 18 6" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="!showStyleSelectorView" class="space-y-3">
|
||||
<button
|
||||
type="button"
|
||||
class="flex w-full items-center justify-between gap-3 rounded-2xl border border-white/20 bg-white/40 px-4 py-3 text-left font-semibold text-slate-900 transition hover:border-emerald-400 hover:bg-white/70 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-400 dark:border-white/10 dark:bg-white/5 dark:text-white"
|
||||
@click="showStyleSelectorView = true"
|
||||
>
|
||||
<div>
|
||||
<p class="text-base">Stile anzeigen</p>
|
||||
<p class="text-sm font-normal text-slate-500 dark:text-slate-400">Lass die KI dein Motiv verzaubern.</p>
|
||||
</div>
|
||||
<span class="flex h-12 w-12 items-center justify-center rounded-full bg-white/60 text-slate-900 shadow-md dark:bg-slate-800/70 dark:text-white">
|
||||
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904a2.25 2.25 0 0 1 0-3.808l.99-.572a1.125 1.125 0 0 0 0-1.948l-.99-.572a2.25 2.25 0 0 1 0-3.808l5.25-3.038A2.25 2.25 0 0 1 17.625 3v18a2.25 2.25 0 0 1-3.563 1.844l-4.249-2.457Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.25a.75.75 0 0 1 .75.75v12a.75.75 0 0 1-1.5 0v-12a.75.75 0 0 1 .75-.75Zm13.5 0a.75.75 0 0 1 .75.75v12a.75.75 0 0 1-1.5 0v-12a.75.75 0 0 1 .75-.75Z" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="showPrintButton"
|
||||
type="button"
|
||||
class="flex w-full items-center justify-between gap-3 rounded-2xl border border-white/10 bg-slate-900/5 px-4 py-3 text-left font-semibold text-slate-900 transition hover:border-cyan-300 hover:bg-cyan-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 dark:border-white/10 dark:bg-white/5 dark:text-white"
|
||||
@click="$emit('print', image)"
|
||||
>
|
||||
<div>
|
||||
<p class="text-base">Drucken</p>
|
||||
<p class="text-sm font-normal text-slate-500 dark:text-slate-400">Sofort den Druckdialog öffnen</p>
|
||||
</div>
|
||||
<span class="flex h-12 w-12 items-center justify-center rounded-full bg-cyan-100 text-cyan-900 shadow-md dark:bg-cyan-400/20 dark:text-cyan-200">
|
||||
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 9V4.5A1.5 1.5 0 0 1 7.5 3h9A1.5 1.5 0 0 1 18 4.5V9m-12 0h12m-12 0H4.5A1.5 1.5 0 0 0 3 10.5v6A1.5 1.5 0 0 0 4.5 18H6m12-9h1.5A1.5 1.5 0 0 1 21 10.5v6a1.5 1.5 0 0 1-1.5 1.5H18m-12 0v4.5A1.5 1.5 0 0 0 7.5 24h9a1.5 1.5 0 0 0 1.5-1.5V18m-12 0h12" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="shouldShowDownload"
|
||||
type="button"
|
||||
class="flex w-full items-center justify-between gap-3 rounded-2xl border border-white/10 bg-slate-900/5 px-4 py-3 text-left font-semibold text-slate-900 transition hover:border-indigo-300 hover:bg-indigo-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-300 dark:border-white/10 dark:bg-white/5 dark:text-white"
|
||||
@click="$emit('download', image)"
|
||||
>
|
||||
<div>
|
||||
<p class="text-base">Herunterladen</p>
|
||||
<p class="text-sm font-normal text-slate-500 dark:text-slate-400">Datei lokal speichern</p>
|
||||
</div>
|
||||
<span class="flex h-12 w-12 items-center justify-center rounded-full bg-indigo-100 text-indigo-900 shadow-md dark:bg-indigo-400/20 dark:text-indigo-200">
|
||||
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v12m0 0 4-4m-4 4-4-4m-5 7.5h18" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="flex w-full items-center justify-between gap-3 rounded-2xl border border-white/10 bg-white/0 px-4 py-3 text-left font-semibold text-slate-900 transition hover:border-rose-300 hover:bg-rose-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-rose-300 dark:border-white/10 dark:bg-white/5 dark:text-white"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<div>
|
||||
<p class="text-base">Schließen</p>
|
||||
<p class="text-sm font-normal text-slate-500 dark:text-slate-400">Zurück zur Galerie</p>
|
||||
</div>
|
||||
<span class="flex h-12 w-12 items-center justify-center rounded-full bg-rose-100 text-rose-900 shadow-md dark:bg-rose-400/20 dark:text-rose-200">
|
||||
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-else class="space-y-4">
|
||||
<div class="flex items-center justify-between text-sm text-slate-400">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center gap-2 rounded-full border border-white/20 px-3 py-1 text-xs uppercase tracking-[0.3em] text-white/80 transition hover:border-emerald-300"
|
||||
@click="showStyleSelectorView = false"
|
||||
>
|
||||
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m10 19-7-7 7-7m-7 7h18" />
|
||||
</svg>
|
||||
Zurück
|
||||
</button>
|
||||
<span>Stilauswahl</span>
|
||||
</div>
|
||||
<StyleSelector
|
||||
class="max-h-[520px] flex-1"
|
||||
:image_id="image?.id ?? image?.image_id"
|
||||
@styleSelected="handleStyleSelected"
|
||||
@close="$emit('close')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<StyleSelector
|
||||
v-else
|
||||
:image_id="image.image_id"
|
||||
@styleSelected="(style, imageId) => $emit('styleSelected', style, imageId)"
|
||||
@back="showStyleSelectorView = false"
|
||||
@close="$emit('close')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { usePage } from '@inertiajs/vue3';
|
||||
import StyleSelector from './StyleSelector.vue';
|
||||
|
||||
const page = usePage();
|
||||
const settings = page.props.settings;
|
||||
|
||||
const props = defineProps({
|
||||
position: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
image: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['close', 'print', 'changeStyle', 'styleSelected', 'download']);
|
||||
const emits = defineEmits(['close', 'print', 'styleSelected', 'download']);
|
||||
|
||||
const isNonLocalAccess = () => {
|
||||
const settings = computed(() => page.props.settings || {});
|
||||
const showPrintButton = computed(() => settings.value.show_print_button ?? true);
|
||||
|
||||
const shouldShowDownload = computed(() => {
|
||||
const hostname = window.location.hostname;
|
||||
return hostname !== 'localhost' &&
|
||||
hostname !== '127.0.0.1' &&
|
||||
!hostname.startsWith('192.168.') &&
|
||||
!hostname.startsWith('10.') &&
|
||||
!hostname.startsWith('172.');
|
||||
};
|
||||
hostname !== '127.0.0.1' &&
|
||||
!hostname.startsWith('192.168.') &&
|
||||
!hostname.startsWith('10.') &&
|
||||
!hostname.startsWith('172.');
|
||||
});
|
||||
|
||||
const showStyleSelectorView = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.image,
|
||||
() => {
|
||||
showStyleSelectorView.value = false;
|
||||
}
|
||||
);
|
||||
|
||||
const imageLabel = computed(() => props.image?.name || 'Ausgewähltes Bild');
|
||||
|
||||
const handleStyleSelected = (style, imageId) => {
|
||||
showStyleSelectorView.value = false;
|
||||
emits('styleSelected', style, imageId);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.context-menu-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5); /* Halbdurchsichtiger Hintergrund */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
background: var(--color-background);
|
||||
border: 1px solid var(--color-text);
|
||||
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: row; /* Bild und Menü nebeneinander */
|
||||
max-width: 90%;
|
||||
height: 80vh; /* 80% of viewport height */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.context-menu-image-preview {
|
||||
flex: 7; /* Takes 60% of the space (6 out of 10 parts) */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.context-menu-image-preview img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: 80%; /* 80% width of its container */
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.context-menu-options {
|
||||
flex: 3; /* Takes 40% of the space (4 out of 10 parts) */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-left: 1px solid var(--color-text); /* Trennlinie zwischen Bild und Menü */
|
||||
min-width: 150px; /* Mindestbreite für das Menü */
|
||||
}
|
||||
|
||||
.context-menu-button {
|
||||
@apply flex items-center justify-start px-4 py-3 font-medium text-white bg-[#0056b3] hover:bg-[#004494] focus:outline-none focus:ring-2 focus:ring-[#0056b3] focus:ring-offset-2 transition ease-in-out duration-150 rounded-md;
|
||||
width: 70%;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--color-text);
|
||||
margin: 5px auto;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.context-menu-button:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user