Files
website/layers/wishlist/app/components/WishlistCard.vue
T
2026-09-30 19:15:57 +02:00

39 lines
1.6 KiB
Vue

<script setup lang="ts">
const props = defineProps<{ book: WishlistBook }>()
const { url: cover, loading } = useWishlistCover(() => props.book)
const imageFailed = ref(false)
const authors = computed(() => props.book.authors.map(wishlistAuthorName).join(', '))
</script>
<template>
<component
:is="book.thalia ? 'a' : 'div'"
:href="book.thalia ?? undefined"
target="_blank"
rel="noopener noreferrer"
class="group block focus-visible:outline-none"
>
<div
class="relative aspect-[2/3] overflow-hidden rounded-md bg-elevated shadow-sm ring-1 ring-default transition duration-200 group-hover:-translate-y-1 group-hover:shadow-lg group-focus-visible:ring-2 group-focus-visible:ring-primary"
>
<img
v-if="cover && !imageFailed"
:src="cover"
:alt="`Cover of ${book.title}`"
loading="lazy"
class="size-full object-cover"
@error="imageFailed = true"
>
<div v-else-if="loading" class="size-full animate-pulse bg-accented" />
<div v-else class="flex size-full flex-col justify-between bg-gradient-to-br from-primary-100 to-primary-200 p-3 text-primary-950 dark:from-primary-900 dark:to-primary-950 dark:text-primary-50">
<p class="font-serif text-base leading-snug font-semibold line-clamp-5">{{ book.title }}</p>
<p class="text-xs opacity-75 line-clamp-2">{{ authors }}</p>
</div>
</div>
<p class="mt-2 text-sm leading-snug font-medium text-highlighted line-clamp-2">{{ book.title }}</p>
<p class="text-xs text-muted line-clamp-1">{{ authors }}</p>
</component>
</template>