Files
myprojplanet_vite/src/components/Dashboard/RecentPosters/RecentPosters.vue
Surya Paolo 6d78f82099 - aggiornamento di tante cose...
- generazione Volantini
- pagina RIS
2025-12-17 10:07:42 +01:00

308 lines
7.0 KiB
Vue

<template>
<div class="recent-posters">
<!-- Loading State -->
<div v-if="isLoading" class="posters-grid">
<div v-for="i in 6" :key="i" class="poster-skeleton">
<q-skeleton type="rect" class="skeleton-image" />
<div class="skeleton-content">
<q-skeleton type="text" width="70%" />
<q-skeleton type="text" width="40%" />
</div>
</div>
</div>
<!-- Empty State -->
<div v-else-if="posters.length === 0" class="empty-state">
<q-icon name="image" size="64px" color="grey-4" />
<h3>Nessuna locandina</h3>
<p>Crea la tua prima locandina per vederla qui</p>
<q-btn
color="primary"
icon="add"
label="Crea Locandina"
@click="$router.push('/posters/poster-generator')"
/>
</div>
<!-- Posters Grid -->
<div v-else class="posters-grid">
<div
v-for="poster in posters"
:key="poster._id"
class="poster-card"
>
<div class="poster-image" @click="$emit('view', poster)">
<img
:src="poster.renderOutput?.png?.url || poster.renderOutput?.jpg?.url || '/placeholder.png'"
:alt="poster.name"
loading="lazy"
/>
<div class="poster-overlay">
<q-btn round color="white" text-color="dark" icon="visibility" size="sm" />
</div>
<q-badge
v-if="poster.metadata?.isFavorite"
color="amber"
floating
class="favorite-badge"
>
<q-icon name="star" size="12px" />
</q-badge>
</div>
<div class="poster-info">
<h3 :title="poster.name">{{ poster.name }}</h3>
<p class="poster-date">
<q-icon name="schedule" size="14px" />
{{ formatDate(poster.createdAt) }}
</p>
</div>
<div class="poster-actions">
<q-btn flat dense round icon="download" size="sm" @click="$emit('download', poster)">
<q-tooltip>Scarica</q-tooltip>
</q-btn>
<q-btn flat dense round icon="edit" size="sm" @click="$emit('edit', poster)">
<q-tooltip>Modifica</q-tooltip>
</q-btn>
<q-btn flat dense round icon="more_vert" size="sm">
<q-menu>
<q-list dense>
<q-item clickable v-close-popup @click="$emit('view', poster)">
<q-item-section avatar><q-icon name="visibility" size="20px" /></q-item-section>
<q-item-section>Visualizza</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="sharePoster(poster)">
<q-item-section avatar><q-icon name="share" size="20px" /></q-item-section>
<q-item-section>Condividi</q-item-section>
</q-item>
<q-separator />
<q-item clickable v-close-popup @click="deletePoster(poster)" class="text-negative">
<q-item-section avatar><q-icon name="delete" size="20px" /></q-item-section>
<q-item-section>Elimina</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useQuasar } from 'quasar';
const props = defineProps<{
posters: any[];
isLoading: boolean;
}>();
const emit = defineEmits<{
(e: 'view', poster: any): void;
(e: 'download', poster: any): void;
(e: 'edit', poster: any): void;
}>();
const $q = useQuasar();
const formatDate = (dateString: string) => {
const date = new Date(dateString);
const now = new Date();
const diff = now.getTime() - date.getTime();
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (minutes < 60) return `${minutes} min fa`;
if (hours < 24) return `${hours} ore fa`;
if (days < 7) return `${days} giorni fa`;
return date.toLocaleDateString('it-IT', {
day: 'numeric',
month: 'short'
});
};
const sharePoster = async (poster: any) => {
try {
if (navigator.share) {
await navigator.share({
title: poster.name,
text: `Guarda la mia locandina: ${poster.content?.title || poster.name}`,
url: window.location.origin + `/posters/${poster._id}`
});
} else {
await navigator.clipboard.writeText(window.location.origin + `/posters/${poster._id}`);
$q.notify({ type: 'positive', message: 'Link copiato!' });
}
} catch (error) {
console.error('Share error:', error);
}
};
const deletePoster = (poster: any) => {
$q.dialog({
title: 'Elimina Locandina',
message: `Vuoi eliminare "${poster.name}"?`,
cancel: true
}).onOk(() => {
$q.notify({ type: 'info', message: 'Eliminazione...' });
// Implement delete
});
};
</script>
<style lang="scss" scoped>
.recent-posters {
min-height: 200px;
}
.posters-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.25rem;
@media (max-width: 900px) {
grid-template-columns: repeat(2, 1fr);
}
@media (max-width: 500px) {
grid-template-columns: 1fr;
}
}
.poster-card {
background: white;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
.poster-overlay {
opacity: 1;
}
}
}
.poster-image {
position: relative;
aspect-ratio: 3/4;
cursor: pointer;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
&:hover img {
transform: scale(1.05);
}
}
.poster-overlay {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.favorite-badge {
top: 0.5rem !important;
right: 0.5rem !important;
}
.poster-info {
padding: 1rem;
h3 {
margin: 0;
font-size: 1rem;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.poster-date {
display: flex;
align-items: center;
gap: 0.25rem;
margin: 0.35rem 0 0;
font-size: 0.8rem;
color: #888;
}
}
.poster-actions {
display: flex;
justify-content: flex-end;
padding: 0 0.5rem 0.75rem;
gap: 0.25rem;
}
// Skeleton
.poster-skeleton {
background: white;
border-radius: 16px;
overflow: hidden;
.skeleton-image {
height: 200px;
}
.skeleton-content {
padding: 1rem;
}
}
// Empty State
.empty-state {
text-align: center;
padding: 3rem 1rem;
background: white;
border-radius: 16px;
h3 {
margin: 1rem 0 0.5rem;
font-size: 1.2rem;
color: #555;
}
p {
color: #888;
margin-bottom: 1.5rem;
}
}
// Dark mode
.body--dark {
.poster-card,
.poster-skeleton,
.empty-state {
background: #1e1e1e;
}
.poster-info h3 {
color: #fff;
}
.empty-state h3 {
color: #ddd;
}
}
</style>