feat(activities): drop image placeholder when an event has no image

Cards without an image no longer render the solid-color 16:9
placeholder + calendar glyph. They go straight to the content area
with the badges (category, price, Yours, status, Past) shown
inline in a small row at the top, so the title and details aren't
pushed below a meaningless filler block.

The placeholderBg computed (hash → HSL) is removed; it was only
feeding the deleted no-image branch.
This commit is contained in:
Padreug 2026-06-04 22:10:38 +02:00 committed by padreug
commit 520bbf46a7

View file

@ -52,13 +52,6 @@ const priceDisplay = computed(() => {
return `${info.price} ${info.currency}` return `${info.price} ${info.currency}`
}) })
const placeholderBg = computed(() => {
// Generate a consistent hue from the event title
const hash = props.event.title.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
const hue = hash % 360
return `hsl(${hue}, 40%, 85%)`
})
const isPast = computed(() => { const isPast = computed(() => {
const a = props.event const a = props.event
const end = a.endDate ?? a.startDate const end = a.endDate ?? a.startDate
@ -72,22 +65,18 @@ const isPast = computed(() => {
class="overflow-hidden cursor-pointer hover:shadow-lg transition-shadow duration-200 flex flex-col" class="overflow-hidden cursor-pointer hover:shadow-lg transition-shadow duration-200 flex flex-col"
@click="emit('click', event)" @click="emit('click', event)"
> >
<!-- Image / Placeholder --> <!-- Image with overlaid badges. Cards without an image skip the
<div class="relative aspect-[16/9] overflow-hidden"> hero area entirely and surface their badges inline at the top
of the content block the solid-color placeholder + calendar
glyph wasn't communicating anything the title + details don't
already. -->
<div v-if="event.image" class="relative aspect-[16/9] overflow-hidden">
<img <img
v-if="event.image"
:src="event.image" :src="event.image"
:alt="event.title" :alt="event.title"
class="w-full h-full object-cover" class="w-full h-full object-cover"
loading="lazy" loading="lazy"
/> />
<div
v-else
class="w-full h-full flex items-center justify-center"
:style="{ backgroundColor: placeholderBg }"
>
<Calendar class="w-12 h-12 text-foreground/20" />
</div>
<!-- Category badge --> <!-- Category badge -->
<Badge <Badge
@ -147,6 +136,37 @@ const isPast = computed(() => {
</div> </div>
<CardContent class="p-4 flex-1 flex flex-col gap-2"> <CardContent class="p-4 flex-1 flex flex-col gap-2">
<!-- Inline badge row (no-image variant). Same badges as the
image-overlay set, just stacked horizontally at the top of
the content area. -->
<div v-if="!event.image" class="flex flex-wrap items-center gap-1.5">
<Badge v-if="categoryLabel" variant="secondary" class="text-xs">
{{ categoryLabel }}
</Badge>
<Badge v-if="priceDisplay" class="text-xs">
{{ priceDisplay }}
</Badge>
<Badge v-if="event.isMine" variant="outline" class="text-xs gap-1">
<User class="w-3 h-3" />
Yours
</Badge>
<Badge
v-if="event.lnbitsStatus && event.lnbitsStatus !== 'approved'"
:variant="event.lnbitsStatus === 'rejected' ? 'destructive' : 'secondary'"
class="text-xs capitalize"
>
{{ event.lnbitsStatus === 'rejected' ? 'Rejected' : 'Pending review' }}
</Badge>
<Badge
v-if="isPast && !(event.lnbitsStatus && event.lnbitsStatus !== 'approved')"
variant="outline"
class="text-xs gap-1"
>
<History class="w-3 h-3" />
{{ t('events.filters.past', 'Past') }}
</Badge>
</div>
<!-- Title + Bookmark --> <!-- Title + Bookmark -->
<div class="flex items-start gap-1"> <div class="flex items-start gap-1">
<h3 class="font-semibold text-foreground line-clamp-2 leading-tight flex-1"> <h3 class="font-semibold text-foreground line-clamp-2 leading-tight flex-1">