59 lines
1.7 KiB
Vue
59 lines
1.7 KiB
Vue
<template>
|
|
<article class="overflow-hidden rounded-2xl border border-border bg-surface-2 transition hover:border-brand-500/40 hover:shadow-md">
|
|
<div class="relative aspect-[16/10] bg-surface-3">
|
|
<img
|
|
v-if="cover"
|
|
:src="cover"
|
|
:alt="business.title"
|
|
class="h-full w-full object-cover"
|
|
loading="lazy"
|
|
/>
|
|
<div
|
|
v-else
|
|
class="flex h-full w-full items-center justify-center text-4xl text-muted/50"
|
|
>
|
|
🏪
|
|
</div>
|
|
<AppBadge
|
|
class="absolute left-2 top-2"
|
|
:tone="business.isActive ? 'success' : 'warning'"
|
|
>
|
|
{{ activeLabel(business.isActive) }}
|
|
</AppBadge>
|
|
</div>
|
|
|
|
<div class="p-3">
|
|
<h3 class="truncate font-semibold text-text">{{ business.title }}</h3>
|
|
<p v-if="business.category" class="mt-0.5 truncate text-xs text-muted">
|
|
{{ business.category.title }}
|
|
</p>
|
|
<p v-if="ownerText" class="mt-1 truncate text-xs text-muted">{{ ownerText }}</p>
|
|
|
|
<div v-if="$slots.actions" class="mt-3 grid gap-1" :class="actionGridClass">
|
|
<slot name="actions" />
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
import type { Business } from '@/api/types';
|
|
import AppBadge from '@/components/ui/AppBadge.vue';
|
|
import { activeLabel } from '@/utils/format';
|
|
import { businessCoverUrl } from '@/utils/media';
|
|
|
|
const props = defineProps<{
|
|
business: Business;
|
|
ownerText?: string | null;
|
|
actionCols?: number;
|
|
}>();
|
|
|
|
const cover = computed(() => businessCoverUrl(props.business.images));
|
|
|
|
const actionGridClass = computed(() => {
|
|
const cols = props.actionCols ?? 3;
|
|
return cols === 2 ? 'grid-cols-2' : 'grid-cols-3';
|
|
});
|
|
</script>
|