feat(activities): refine activity card for pending/rejected + compact
- Wash out pending/rejected events with opacity-50 + grayscale on a wrapper div so the operator sees at a glance the event isn't live, not just the small badge. - Pull the status badge OUT of the wash-out wrapper and absolute- position it on Card root (bottom-2 left-2, z-10) so it stays in full color above the dim card. Both pending and rejected use the destructive token — the label text differentiates the two states. Bottom-left so it doesn't collide with the category chip on full cards or the thumbnail on compact ones. - Compact rows in the Hosting view now show a small left-aligned thumbnail (w-20 h-20, self-center, ml-3, rounded-md) when the event carries an image — host can still recognize each event at a glance without paying the visual weight of a full hero. - Card root becomes `relative overflow-hidden`; the wrapper div owns the conditional flex-row (compact) / flex-col (default) layout and the opacity/grayscale toggling.
This commit is contained in:
parent
5517aebb6a
commit
a12ed8dd6a
2 changed files with 57 additions and 32 deletions
|
|
@ -62,19 +62,46 @@ const isPast = computed(() => {
|
|||
if (!end || isNaN(end.getTime())) return false
|
||||
return end.getTime() < Date.now()
|
||||
})
|
||||
|
||||
// Pending / rejected events get a washed-out look so the user
|
||||
// sees at a glance the event isn't live, not just the small badge.
|
||||
const isNonApproved = computed(
|
||||
() => !!props.activity.lnbitsStatus && props.activity.lnbitsStatus !== 'approved',
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card
|
||||
class="overflow-hidden cursor-pointer hover:shadow-lg transition-shadow duration-200 flex flex-col"
|
||||
class="relative cursor-pointer hover:shadow-lg transition-shadow duration-200"
|
||||
@click="emit('click', activity)"
|
||||
>
|
||||
<!-- Wash-out wrapper. The pending/rejected status badge below sits
|
||||
OUTSIDE this wrapper so it stays in full color and reads
|
||||
clearly even when the card is dimmed + desaturated. -->
|
||||
<div
|
||||
class="transition-opacity duration-200"
|
||||
:class="[
|
||||
compact ? 'flex flex-row' : 'flex flex-col',
|
||||
isNonApproved ? 'opacity-50 grayscale hover:opacity-90' : '',
|
||||
]"
|
||||
>
|
||||
<!-- Compact thumbnail — small square preview on the left of the
|
||||
row when the event carries an image. `self-center` keeps it
|
||||
vertically centered against a taller content column so we
|
||||
don't get a top-anchored thumb with dead space below. -->
|
||||
<img
|
||||
v-if="compact && activity.image"
|
||||
:src="activity.image"
|
||||
:alt="activity.title"
|
||||
class="w-20 h-20 object-cover shrink-0 self-center ml-3 rounded-md"
|
||||
loading="lazy"
|
||||
/>
|
||||
<!-- Image with overlaid badges. Cards without an image (or in
|
||||
compact mode) skip the 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="activity.image && !compact" class="relative aspect-[16/9] overflow-hidden">
|
||||
<div v-if="activity.image && !compact" class="relative aspect-[16/9] overflow-hidden rounded-t-lg">
|
||||
<img
|
||||
:src="activity.image"
|
||||
:alt="activity.title"
|
||||
|
|
@ -110,27 +137,13 @@ const isPast = computed(() => {
|
|||
{{ priceDisplay }}
|
||||
</Badge>
|
||||
|
||||
<!-- Pending/rejected overlay for the creator's own non-approved
|
||||
drafts. Only present when the activity originated from a
|
||||
local LNbits event (Nostr-sourced activities have no
|
||||
lnbitsStatus). -->
|
||||
<!-- Past badge — shown when the activity has already ended. The
|
||||
pending/rejected status badge that used to share this slot
|
||||
is now an absolute overlay on Card root, above the wash-out,
|
||||
so we still suppress Past when isNonApproved (the status
|
||||
badge is more actionable in that case). -->
|
||||
<Badge
|
||||
v-if="activity.lnbitsStatus && activity.lnbitsStatus !== 'approved'"
|
||||
:variant="activity.lnbitsStatus === 'rejected' ? 'destructive' : 'secondary'"
|
||||
class="absolute bottom-2 left-2 text-xs capitalize"
|
||||
>
|
||||
{{ activity.lnbitsStatus === 'rejected' ? 'Rejected' : 'Pending review' }}
|
||||
</Badge>
|
||||
|
||||
<!-- Past badge — shown when the activity has already ended.
|
||||
Only relevant on the feed when the "Past events" filter
|
||||
chip is toggled on (otherwise these cards aren't rendered);
|
||||
on the detail page the card view isn't used. Suppressed
|
||||
when a pending/rejected status badge is taking the same
|
||||
slot — that case is the creator's own past draft, which is
|
||||
vanishingly rare and the status hint is more actionable. -->
|
||||
<Badge
|
||||
v-if="isPast && !(activity.lnbitsStatus && activity.lnbitsStatus !== 'approved')"
|
||||
v-if="isPast && !isNonApproved"
|
||||
variant="outline"
|
||||
class="absolute bottom-2 left-2 text-xs gap-1 bg-background/80 backdrop-blur"
|
||||
>
|
||||
|
|
@ -158,14 +171,7 @@ const isPast = computed(() => {
|
|||
Yours
|
||||
</Badge>
|
||||
<Badge
|
||||
v-if="activity.lnbitsStatus && activity.lnbitsStatus !== 'approved'"
|
||||
:variant="activity.lnbitsStatus === 'rejected' ? 'destructive' : 'secondary'"
|
||||
class="text-xs capitalize"
|
||||
>
|
||||
{{ activity.lnbitsStatus === 'rejected' ? 'Rejected' : 'Pending review' }}
|
||||
</Badge>
|
||||
<Badge
|
||||
v-if="isPast && !(activity.lnbitsStatus && activity.lnbitsStatus !== 'approved')"
|
||||
v-if="isPast && !isNonApproved"
|
||||
variant="outline"
|
||||
class="text-xs gap-1"
|
||||
>
|
||||
|
|
@ -251,5 +257,22 @@ const isPast = computed(() => {
|
|||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</div>
|
||||
|
||||
<!-- Status badge — absolutely positioned on Card root so it sits
|
||||
ABOVE the wash-out wrapper and keeps its full color.
|
||||
Pending + rejected both lean on the destructive token so the
|
||||
non-approved state reads as "needs attention" in every theme;
|
||||
the label text differentiates the two specific states.
|
||||
Bottom-right with a slight downward spill so it anchors
|
||||
visually without competing with the category chip in the
|
||||
badge row (full cards) or the thumbnail (compact cards). -->
|
||||
<Badge
|
||||
v-if="isNonApproved"
|
||||
variant="destructive"
|
||||
class="absolute -bottom-1 right-2 z-10 text-xs capitalize shadow"
|
||||
>
|
||||
{{ activity.lnbitsStatus === 'rejected' ? 'Rejected' : 'Pending review' }}
|
||||
</Badge>
|
||||
</Card>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -52,10 +52,12 @@ const { t } = useI18n()
|
|||
</div>
|
||||
|
||||
<!-- Activity grid — compact mode collapses to a single column of
|
||||
tight rows; default mode is the responsive card grid. -->
|
||||
tight rows; default mode is the responsive card grid. The
|
||||
compact gap is bumped a notch so the status badge spilling
|
||||
past the card's bottom edge has room to sit between cards. -->
|
||||
<div
|
||||
v-else
|
||||
:class="compact ? 'flex flex-col gap-2' : 'grid gap-4 sm:grid-cols-2 lg:grid-cols-3'"
|
||||
:class="compact ? 'flex flex-col gap-4' : 'grid gap-4 sm:grid-cols-2 lg:grid-cols-3'"
|
||||
>
|
||||
<ActivityCard
|
||||
v-for="activity in activities"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue