frontend/src/views/CollectionView/CollectionMerchCard.vue
nquidox c74032d1d0
All checks were successful
/ Make image (push) Successful in 47s
labels added
2025-10-29 20:59:03 +03:00

138 lines
2.8 KiB
Vue

<script setup>
import BoxIcon from '@/components/icons/BoxIcon.vue'
import { useMerchImagesApi } from '@/api/merchImages.js'
import { computed, onMounted, ref } from 'vue'
import LabelDotTemplate from '@/components/LabelDotTemplate.vue'
import { useLabelsStore } from '@/stores/labelsStore.js'
const { getImageUrl } = useMerchImagesApi()
const props = defineProps({
merch: {
type: Object,
required: true,
},
labels: {
type: Array,
default: () => [],
},
})
const store = useLabelsStore()
const resolvedLabelDots = computed(() => {
const labelMap = new Map()
for (const label of store.labels) {
labelMap.set(label.label_uuid, label)
}
return props.labels
.map(uuid => labelMap.get(uuid))
.filter(Boolean)
})
const fileList = ref([])
onMounted(async () => {
try {
const imgUrl = getImageUrl(props.merch.merch_uuid, 'thumbnail')
await new Promise((resolve, reject) => {
const img = new Image()
img.src = imgUrl
img.onload = () => resolve(imgUrl)
img.onerror = () => reject(new Error('Image not found'))
})
fileList.value = [
{
name: 'thumbnail.jpg',
url: imgUrl,
status: 'finished',
},
]
} catch (error) {
fileList.value = []
if (!error.message.includes('404')) {
console.error('Error getting thumbnail: ', error)
}
}
})
</script>
<template>
<n-card class="responsive-card">
<template #header>
<h3 class="card-title">{{ merch.name }}</h3>
<div v-if="resolvedLabelDots.length > 0" class="label-dots">
<LabelDotTemplate
v-for="label in resolvedLabelDots"
:key="label.label_uuid"
:color="label.color"
:bg_color="label.bg_color"
/>
</div>
</template>
<template #cover>
<div class="cover-wrapper">
<img
v-if="fileList.length > 0 && fileList[0].url"
:src="fileList[0].url"
alt="Thumbnail"
class="thumbnail"
/>
<BoxIcon v-else />
</div>
</template>
</n-card>
</template>
<style scoped>
.responsive-card {
width: 180px;
height: 240px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-title {
margin: 0;
font-size: 14px;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
white-space: normal;
}
.cover-wrapper {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 12px 0;
overflow: hidden;
}
.thumbnail {
width: 100%;
height: auto;
max-width: 80%;
object-fit: contain;
}
.cover-wrapper :deep(svg) {
width: 100%;
height: auto;
max-width: 80%;
}
.label-dots {
display: flex;
gap: 6px;
flex-wrap: wrap;
justify-content: right;
}
</style>