site-panzai/components/DishCard.vue

64 lines
2.9 KiB
Vue
Raw Normal View History

2026-11-13 13:57:04 +01:00
<script setup lang="ts">
import type { Dish } from '~/server/utils/store'
const props = withDefaults(defineProps<{ dish: Dish, layout?: 'grid' | 'row' }>(), { layout: 'grid' })
const { open } = useCustomize()
const { open: shopOpen } = useShop()
const sizes = computed(() => sizesOf(props.dish))
const can = computed(() => orderable(props.dish) && shopOpen.value)
const status = computed(() => !props.dish.available ? 'Rupture' : !orderable(props.dish) ? 'Bientôt' : !shopOpen.value ? 'En pause' : '')
</script>
<template>
<article class="dish card hover-lift" :class="[layout, { off: !dish.available }]">
<div class="photo wood">
<DishPhoto :img="dish.img" :alt="dish.name" />
<span v-if="dish.badge" class="badge tag" :class="`badge-${dish.badge.tone}`">{{ dish.badge.label }}</span>
<span v-if="!dish.available" class="badge tag-off">Rupture de stock</span>
</div>
<div class="body">
<h3>{{ dish.name }}</h3>
<p class="desc">{{ dish.desc }}</p>
<div class="foot">
<p class="prices">
<template v-for="(s, i) in sizes" :key="s">
<span v-if="i" class="muted"> · </span>
<span class="muted">{{ s }}</span> <strong class="price">{{ eur(dish.prices[s]) }}</strong>
</template>
</p>
<button v-if="can" class="btn btn-primary btn-icon add" type="button" :aria-label="`Ajouter ${dish.name}`" @click="open(dish)">
<Icon name="plus" :size="22" :stroke="3" />
</button>
<span v-else class="chip status">{{ status }}</span>
</div>
</div>
</article>
</template>
<style scoped>
.dish { overflow: hidden; display: flex; flex-direction: column; }
.photo { position: relative; height: 190px; }
.photo :deep(.dish-photo) { position: absolute; inset: 12px 7% 6px; }
.tag { position: absolute; left: 12px; top: 12px; }
.tag-off { position: absolute; right: 12px; top: 12px; background: var(--danger); color: var(--bg); }
.body { flex: 1; padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 6px; }
h3 { font-size: 19px; font-weight: 800; color: var(--white); }
.desc { font-size: 14px; opacity: .78; }
.foot { margin-top: auto; padding-top: 8px; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.prices { font-size: 14px; }
.prices .price { font-size: 17px; }
.status { font-size: 13px; padding: 8px 12px; background: var(--surface-2); }
.off .photo { filter: grayscale(.8) brightness(.7); }
/* Variante liste (mobile) */
.row { flex-direction: row; gap: 14px; padding: 12px; }
.row .photo { flex: none; width: 112px; height: 124px; border-radius: 16px; overflow: hidden; }
.row .photo :deep(.dish-photo) { inset: 14px 4px 10px; }
.row .tag { left: 6px; top: 6px; font-size: 10px; padding: 3px 7px; }
.row .tag-off { display: none; }
.row .body { padding: 0; }
.row h3 { font-size: 17px; }
.row .desc { font-size: 13px; }
.row .prices .price { font-size: 15px; }
</style>