138 lines
2.8 KiB
Vue
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>
|