site-panzai/pages/menu.vue
2026-11-13 13:57:04 +01:00

101 lines
5.1 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
useHead({ title: 'La carte — PANZAÏ Thonon' })
const { dishes, open, wait } = useShop()
const { mode } = useCart()
const cats = [
{ id: 'wok', label: 'Plats au wok' },
{ id: 'baguette', label: 'Baguette' },
{ id: 'boissons', label: 'Boissons' },
{ id: 'desserts', label: 'Desserts' }
] as const
const byCat = (c: string) => dishes.value.filter(d => d.cat === c)
const active = ref('wok')
// Onglet actif suivant le scroll
onMounted(() => {
const io = new IntersectionObserver((entries) => {
for (const e of entries) if (e.isIntersecting) active.value = e.target.id
}, { rootMargin: '-40% 0px -55% 0px' })
cats.forEach(c => { const el = document.getElementById(c.id); if (el) io.observe(el) })
onBeforeUnmount(() => io.disconnect())
})
const isDesktop = ref(false)
onMounted(() => {
const mq = window.matchMedia('(min-width: 1024px)')
isDesktop.value = mq.matches
mq.addEventListener('change', e => { isDesktop.value = e.matches })
})
</script>
<template>
<main>
<section class="band">
<LeafMonstera class="band-leaf" />
<div class="container band-in">
<div class="grow">
<h1 class="display" style="font-size: clamp(36px, 5vw, 56px)">La carte</h1>
<p class="muted" style="margin-top: 8px">Tout est fait minute au wok. Taille L ou XL, bœuf, crevettes ou poulet. 100 % halal.</p>
<p v-if="!open" class="pause"><span class="dot dot-red" /> Les commandes sont en pause pour le moment. Tu peux consulter la carte.</p>
</div>
<div class="seg" role="group" aria-label="Mode de commande">
<button type="button" :aria-pressed="mode === 'livraison'" @click="mode = 'livraison'">Livraison · 30–40 min</button>
<button type="button" :aria-pressed="mode === 'retrait'" @click="mode = 'retrait'">Retrait · ~{{ wait }} min</button>
</div>
</div>
</section>
<nav class="tabs" aria-label="Catégories">
<div class="container tabs-in">
<a v-for="c in cats" :key="c.id" :href="`#${c.id}`" :class="{ on: active === c.id }">{{ c.label }}<span class="n">{{ byCat(c.id).length || '—' }}</span></a>
</div>
</nav>
<div class="container layout">
<div class="dishes">
<section v-for="c in cats" :id="c.id" :key="c.id" class="cat" :aria-labelledby="`h-${c.id}`">
<h2 :id="`h-${c.id}`" class="eyebrow">{{ c.label }}</h2>
<div v-if="byCat(c.id).length" class="grid">
<DishCard v-for="d in byCat(c.id)" :key="d.id" :dish="d" :layout="isDesktop ? 'grid' : 'row'" />
</div>
<div v-else class="soon">
<div v-for="n in 2" :key="n" class="soon-card"><div class="soon-img" /><p class="strong">[{{ c.id === 'boissons' ? 'Boisson' : 'Dessert' }} {{ n }}]</p><p class="price small">[PRIX]</p></div>
</div>
</section>
</div>
<div class="side"><CartSummary /></div>
</div>
</main>
</template>
<style scoped>
.band { position: relative; overflow: hidden; border-bottom: 1px solid rgba(243,227,195,.06); }
.band-leaf { position: absolute; right: -70px; top: -60px; width: 240px; transform: rotate(-20deg); }
.band-in { position: relative; display: flex; flex-wrap: wrap; align-items: flex-end; gap: 20px; padding-block: 32px 24px; }
.pause { margin-top: 12px; display: inline-flex; align-items: center; gap: 8px; padding: 10px 14px; border-radius: 12px; background: rgba(232,98,42,.12); border: 1px solid rgba(232,98,42,.4); font-weight: 700; font-size: 14px; }
.seg { width: 100%; max-width: 440px; }
.tabs { position: sticky; top: 70px; z-index: 30; background: rgba(20,16,13,.92); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid rgba(243,227,195,.06); }
.tabs-in { display: flex; gap: 8px; overflow-x: auto; padding-block: 10px; scrollbar-width: none; }
.tabs a { flex: none; display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; border-radius: 999px; background: var(--surface); color: var(--cream); font-size: 14px; font-weight: 700; text-decoration: none; }
.tabs a.on { background: var(--grad); color: var(--bg); font-weight: 800; }
.tabs .n { font-size: 12px; opacity: .7; }
.layout { display: flex; gap: 28px; align-items: flex-start; padding-top: 24px; }
.dishes { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 36px; }
.cat { scroll-margin-top: 140px; }
.cat h2 { margin-bottom: 14px; }
.grid { display: flex; flex-direction: column; gap: 12px; }
.side { display: none; }
.soon { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.soon-card { padding: 14px; border-radius: 18px; background: var(--surface); border: 1px dashed rgba(243,227,195,.2); display: flex; flex-direction: column; gap: 8px; }
.soon-img { height: 80px; border-radius: 12px; background: var(--surface-2); }
@media (min-width: 1024px) {
.tabs { display: none; }
.layout { padding-top: 32px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; }
.side { display: block; flex: none; width: 350px; position: sticky; top: 92px; }
}
</style>