Add list search, compact business cards, registration approval queue, and Montime branding.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,32 @@
|
||||
<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">
|
||||
<article
|
||||
class="flex items-center gap-3 rounded-xl border border-border bg-surface-2 p-2.5 transition hover:border-brand-500/40 hover:shadow-sm"
|
||||
>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<div class="min-w-0 flex-1">
|
||||
<h3 class="truncate text-sm 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-0.5 truncate text-xs text-muted">{{ ownerText }}</p>
|
||||
</div>
|
||||
<AppBadge
|
||||
class="shrink-0 !px-1.5 !py-0.5 text-[10px]"
|
||||
:tone="business.isActive ? 'success' : 'warning'"
|
||||
>
|
||||
{{ activeLabel(business.isActive) }}
|
||||
</AppBadge>
|
||||
</div>
|
||||
|
||||
<div v-if="$slots.actions" class="mt-2 flex flex-wrap gap-1">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="relative h-14 w-14 shrink-0 overflow-hidden rounded-lg bg-surface-3 sm:h-16 sm:w-16"
|
||||
>
|
||||
<img
|
||||
v-if="cover"
|
||||
:src="cover"
|
||||
@@ -10,28 +36,10 @@
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
class="flex h-full w-full items-center justify-center text-4xl text-muted/50"
|
||||
class="flex h-full w-full items-center justify-center text-xl 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>
|
||||
@@ -46,13 +54,7 @@ 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>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<AppInput
|
||||
:id="id"
|
||||
v-model="model"
|
||||
type="search"
|
||||
:label="label"
|
||||
:placeholder="placeholder"
|
||||
autocomplete="off"
|
||||
enterkeyhint="search"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import AppInput from '@/components/ui/AppInput.vue';
|
||||
|
||||
const model = defineModel<string>({ default: '' });
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
id?: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
id: 'search',
|
||||
placeholder: 'جستجو…',
|
||||
},
|
||||
);
|
||||
</script>
|
||||
Reference in New Issue
Block a user