This commit is contained in:
xds
2026-02-20 13:10:50 +03:00
parent b0ce251914
commit 4136f42e70
6 changed files with 403 additions and 195 deletions

View File

@@ -26,6 +26,8 @@ import FileUpload from 'primevue/fileupload'
import ConfirmDialog from 'primevue/confirmdialog'
import InputText from 'primevue/inputtext'
import DatePicker from 'primevue/datepicker'
import Tag from 'primevue/tag'
import GenerationPreviewModal from '../components/GenerationPreviewModal.vue'
const route = useRoute()
const router = useRouter()
@@ -188,10 +190,16 @@ const qualityOptions = ref([
{ key: 'FOURK', value: '4K' }
])
const aspectRatioOptions = ref([
{ key: "NINESIXTEEN", value: "9:16" },
{ key: "FOURTHREE", value: "4:3" },
{ key: "ONEONE", value: "1:1" },
{ key: "TWOTHREE", value: "2:3" },
{ key: "THREETWO", value: "3:2" },
{ key: "THREEFOUR", value: "3:4" },
{ key: "SIXTEENNINE", value: "16:9" }
{ key: "FOURTHREE", value: "4:3" },
{ key: "FOURFIVE", value: "4:5" },
{ key: "FIVEFOUR", value: "5:4" },
{ key: "NINESIXTEEN", value: "9:16" },
{ key: "SIXTEENNINE", value: "16:9" },
{ key: "TWENTYONENINE", value: "21:9" }
])
// Removed duplicate characters ref
@@ -594,29 +602,13 @@ const useResultAsAsset = (gen) => {
const isImagePreviewVisible = ref(false)
const previewImages = ref([])
const previewIndex = ref(0)
const openImagePreview = (imageList, startIdx = 0) => {
// imageList should now be [{url, gen}]
previewImages.value = imageList
previewIndex.value = startIdx
isImagePreviewVisible.value = true
}
const prevPreview = () => {
if (previewIndex.value > 0) previewIndex.value--
}
const nextPreview = () => {
if (previewIndex.value < previewImages.value.length - 1) previewIndex.value++
}
// Global keyboard nav for preview modal (Safari doesn't focus Dialog)
const handlePreviewKeydown = (e) => {
if (e.key === 'ArrowLeft') { prevPreview(); e.preventDefault() }
if (e.key === 'ArrowRight') { nextPreview(); e.preventDefault() }
if (e.key === 'Escape') { isImagePreviewVisible.value = false; e.preventDefault() }
}
watch(isImagePreviewVisible, (visible) => {
if (visible) window.addEventListener('keydown', handlePreviewKeydown)
else window.removeEventListener('keydown', handlePreviewKeydown)
})
onUnmounted(() => window.removeEventListener('keydown', handlePreviewKeydown))
// --- Computeds ---
const groupedGenerations = computed(() => {
@@ -1021,7 +1013,7 @@ watch(viewMode, (v) => {
class="relative group/img cursor-pointer aspect-[4/3]">
<img :src="API_URL + '/assets/' + res + '?thumbnail=true'"
class="w-full h-full object-cover"
@click="openImagePreview(gen.result_list.map(r => API_URL + '/assets/' + r), resIdx)" />
@click="openImagePreview(gen.result_list.map(r => ({ url: API_URL + '/assets/' + r, gen: gen })), resIdx)" />
<!-- Per-image hover overlay -->
<div
class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent opacity-0 group-hover/img:opacity-100 transition-opacity duration-200 pointer-events-none">
@@ -1100,7 +1092,7 @@ watch(viewMode, (v) => {
<div v-for="(img, idx) in allGalleryImages" :key="img.assetId"
class="aspect-[2/3] relative rounded-xl overflow-hidden group bg-slate-800 border-2 transition-all cursor-pointer"
:class="isSelectMode && selectedAssetIds.has(img.assetId) ? 'border-violet-500 ring-2 ring-violet-500/30' : 'border-white/5 hover:border-violet-500/50'"
@click="isSelectMode ? toggleImageSelection(img.assetId) : openImagePreview(allGalleryImages.map(i => i.url), idx)">
@click="isSelectMode ? toggleImageSelection(img.assetId) : openImagePreview(allGalleryImages, idx)">
<img :src="img.thumbnailUrl" class="w-full h-full object-cover" />
@@ -1422,45 +1414,15 @@ watch(viewMode, (v) => {
</template>
</Dialog>
<!-- Preview Modal with Slider -->
<Dialog v-model:visible="isImagePreviewVisible" modal dismissableMask
:style="{ width: '90vw', maxWidth: '1200px', background: 'transparent', boxShadow: 'none' }"
:pt="{ root: { class: '!bg-transparent !border-none !shadow-none' }, header: { class: '!hidden' }, content: { class: '!bg-transparent !p-0' } }"
@keydown.left.prevent="prevPreview" @keydown.right.prevent="nextPreview">
<div class="relative flex items-center justify-center h-[90vh]" @click="isImagePreviewVisible = false">
<!-- Main image -->
<img v-if="previewImages.length > 0" :src="previewImages[previewIndex]"
class="max-w-full max-h-full object-contain rounded-xl shadow-2xl" @click.stop />
<!-- Prev arrow -->
<button v-if="previewImages.length > 1 && previewIndex > 0" @click.stop="prevPreview"
class="absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full bg-black/60 hover:bg-black/80 backdrop-blur-sm flex items-center justify-center text-white transition-all shadow-lg z-20">
<i class="pi pi-chevron-left" style="font-size: 16px"></i>
</button>
<!-- Next arrow -->
<button v-if="previewImages.length > 1 && previewIndex < previewImages.length - 1"
@click.stop="nextPreview"
class="absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full bg-black/60 hover:bg-black/80 backdrop-blur-sm flex items-center justify-center text-white transition-all shadow-lg z-20">
<i class="pi pi-chevron-right" style="font-size: 16px"></i>
</button>
<!-- Counter badge -->
<div v-if="previewImages.length > 1"
class="absolute top-4 right-4 bg-black/60 backdrop-blur-sm text-white text-sm font-bold px-3 py-1 rounded-full z-20">
{{ previewIndex + 1 }} / {{ previewImages.length }}
</div>
<!-- Dot indicators -->
<div v-if="previewImages.length > 1"
class="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2 z-20">
<button v-for="(img, idx) in previewImages" :key="'prev-dot-' + idx"
@click.stop="previewIndex = idx" class="w-2.5 h-2.5 rounded-full transition-all"
:class="previewIndex === idx ? 'bg-white scale-125' : 'bg-white/40 hover:bg-white/60'">
</button>
</div>
</div>
</Dialog>
<GenerationPreviewModal
v-model:visible="isImagePreviewVisible"
:preview-images="previewImages"
:initial-index="previewIndex"
:api-url="dataService.API_URL || API_URL"
@reuse-prompt="reusePrompt"
@reuse-asset="reuseAssets"
@use-result-as-asset="useResultAsAsset"
/>
<!-- Add to Content Plan Dialog -->
<Dialog v-model:visible="showAddToPlanDialog" header="Add to content plan" modal :style="{ width: '420px' }"