Ingredients as many-to-many relations + VS Code/Antigravity launch.json
- new ingredients collection (uid, name, emoji icon, diet_class) synced by update-menu.mjs; menu_items.ingredients is an M2M relation — the script maps data-file uids to fresh PB record ids - diet select removed: the green/red FSSAI badge is derived (non-veg when any linked ingredient is non-veg); 164 items tagged (11 ingredients) - menu cards render ingredient chips (icon + name) under the description - migration 1788500200_menu_ingredients.js (idempotent create — app.save returns nil on success in the JSVM, so don't test its return value) - .vscode/launch.json: PocketBase + Vite dev, build+preview, menu sync, full-stack compound (dev PB on :8091 — 8090 is taken on this host)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react'
|
||||
import type { MenuCategory, MenuItem } from '~/lib/types'
|
||||
import type { Ingredient, MenuCategory, MenuItem } from '~/lib/types'
|
||||
|
||||
const CATEGORY_ICONS: Record<string, string> = {
|
||||
'brew-bites': 'tapas',
|
||||
@@ -18,9 +18,11 @@ const CATEGORY_ICONS: Record<string, string> = {
|
||||
export function MenuBrowser({
|
||||
categories,
|
||||
items,
|
||||
ingredientIndex,
|
||||
}: {
|
||||
categories: MenuCategory[]
|
||||
items: MenuItem[]
|
||||
ingredientIndex: Map<string, Ingredient>
|
||||
}) {
|
||||
const [active, setActive] = React.useState<string>('all')
|
||||
|
||||
@@ -54,7 +56,7 @@ export function MenuBrowser({
|
||||
<section className="mx-auto w-full max-w-7xl px-grid-margin py-space-xl">
|
||||
<div className="grid grid-cols-1 gap-grid-gutter md:grid-cols-2">
|
||||
{visible.map((item) => (
|
||||
<MenuCard key={item.uid} item={item} />
|
||||
<MenuCard key={item.uid} item={item} ingredientIndex={ingredientIndex} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
@@ -67,9 +69,27 @@ function formatPrice(price: number): string {
|
||||
return Number.isInteger(price) ? String(price) : price.toFixed(2)
|
||||
}
|
||||
|
||||
function MenuCard({ item }: { item: MenuItem }) {
|
||||
function resolveIngredients(
|
||||
item: MenuItem,
|
||||
ingredientIndex: Map<string, Ingredient>,
|
||||
): Ingredient[] {
|
||||
return (item.ingredients ?? []).flatMap((key) => {
|
||||
const ing = ingredientIndex.get(key)
|
||||
return ing ? [ing] : []
|
||||
})
|
||||
}
|
||||
|
||||
function MenuCard({
|
||||
item,
|
||||
ingredientIndex,
|
||||
}: {
|
||||
item: MenuItem
|
||||
ingredientIndex: Map<string, Ingredient>
|
||||
}) {
|
||||
const icon = CATEGORY_ICONS[item.category] ?? 'restaurant'
|
||||
const showFooter = Boolean(item.pairing || item.tag)
|
||||
const ingredients = resolveIngredients(item, ingredientIndex)
|
||||
const isVeg = !ingredients.some((ing) => ing.diet_class === 'nonveg')
|
||||
|
||||
return (
|
||||
<div className="flex flex-col overflow-hidden rounded-xl bg-surface-container shadow-md transition-all duration-300 hover:shadow-xl">
|
||||
@@ -78,13 +98,13 @@ function MenuCard({ item }: { item: MenuItem }) {
|
||||
className="relative h-64 w-full bg-cover bg-center"
|
||||
style={{ backgroundImage: `url('${item.image}')` }}
|
||||
>
|
||||
<ItemBadges item={item} />
|
||||
<ItemBadges isVeg={isVeg} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative flex h-32 w-full items-center justify-center bg-surface-container-high">
|
||||
<span className="material-symbols-outlined text-[44px] text-primary/60">{icon}</span>
|
||||
<div className="absolute right-space-sm top-space-sm">
|
||||
<ItemBadges item={item} />
|
||||
<ItemBadges isVeg={isVeg} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -105,6 +125,7 @@ function MenuCard({ item }: { item: MenuItem }) {
|
||||
{item.description ? (
|
||||
<p className="text-body-md text-on-surface-variant">{item.description}</p>
|
||||
) : null}
|
||||
{ingredients.length > 0 ? <IngredientChips ingredients={ingredients} /> : null}
|
||||
</div>
|
||||
|
||||
{showFooter ? (
|
||||
@@ -136,9 +157,8 @@ function MenuCard({ item }: { item: MenuItem }) {
|
||||
)
|
||||
}
|
||||
|
||||
function ItemBadges({ item }: { item: MenuItem }) {
|
||||
if (item.diet !== 'veg' && item.diet !== 'nonveg') return null
|
||||
return <DietBadge isVeg={item.diet === 'veg'} />
|
||||
function ItemBadges({ isVeg }: { isVeg: boolean }) {
|
||||
return <DietBadge isVeg={isVeg} />
|
||||
}
|
||||
|
||||
/** FSSAI-style dietary mark: green square for veg, red for non-veg. */
|
||||
@@ -155,6 +175,24 @@ function DietBadge({ isVeg }: { isVeg: boolean }) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Ingredient icons (emoji) with names on hover. */
|
||||
function IngredientChips({ ingredients }: { ingredients: Ingredient[] }) {
|
||||
return (
|
||||
<div className="mt-space-md flex flex-wrap items-center gap-space-sm">
|
||||
{ingredients.map((ing) => (
|
||||
<span
|
||||
key={ing.uid}
|
||||
title={ing.name}
|
||||
className="flex items-center gap-1 rounded bg-surface-container-high px-space-sm py-0.5 text-body-sm text-on-surface-variant"
|
||||
>
|
||||
<span aria-hidden="true">{ing.icon}</span>
|
||||
{ing.name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FilterTab({
|
||||
label,
|
||||
active,
|
||||
|
||||
+180
-167
@@ -6,13 +6,16 @@
|
||||
* edit this file, commit, then run scripts/update-menu.mjs to refresh the
|
||||
* live PocketBase data.
|
||||
*
|
||||
* Schema notes (v3, POS-friendly):
|
||||
* Schema notes (v4, POS-friendly):
|
||||
* - Variants are separate products whenever their price differs
|
||||
* ("Penne Arrabiata" + variant "Veg" 589 / "Chicken" 639).
|
||||
* - Same-price choice lists (flavours, sauces) stay on one item in `tag`.
|
||||
* - price: number, rupees with optional paise after the decimal point
|
||||
* (449 = ₹449, 449.5 = ₹449.50).
|
||||
* - diet: 'veg' | 'nonveg' | 'mixed' (PB bools can't be null, so a select is used).
|
||||
* - ingredients: many-to-many with the INGREDIENTS list below (uids here;
|
||||
* the sync script maps them to PocketBase record ids). The site derives
|
||||
* each item's veg/non-veg badge from its ingredients and renders each
|
||||
* ingredient's icon.
|
||||
* - sku: stable GB-<CAT>-<NNN> code for POS mapping.
|
||||
* - tax_category: default "food-5-gst" — adjust per item if the POS needs it.
|
||||
* - available: false hides an item (86'd) without deleting it.
|
||||
@@ -32,6 +35,25 @@ export const MENU_CATEGORIES = [
|
||||
{ uid: 'cat-pizzas', slug: 'pizzas', name: 'Pizzas', sort: 11 },
|
||||
]
|
||||
|
||||
/**
|
||||
* Ingredients / dietary markers. `icon` is an emoji shown on menu cards;
|
||||
* `diet_class` drives the veg / non-veg badge (an item is non-veg when any
|
||||
* of its ingredients is non-veg).
|
||||
*/
|
||||
export const INGREDIENTS = [
|
||||
{ uid: 'nuts', name: 'Nuts', icon: '🥜', diet_class: 'veg', sort: 1 },
|
||||
{ uid: 'dairy', name: 'Dairy', icon: '🥛', diet_class: 'veg', sort: 2 },
|
||||
{ uid: 'gluten', name: 'Gluten', icon: '🌾', diet_class: 'veg', sort: 3 },
|
||||
{ uid: 'soy', name: 'Soy', icon: '🌱', diet_class: 'veg', sort: 4 },
|
||||
{ uid: 'mushroom', name: 'Mushroom', icon: '🍄', diet_class: 'veg', sort: 5 },
|
||||
{ uid: 'egg', name: 'Egg', icon: '🥚', diet_class: 'nonveg', sort: 6 },
|
||||
{ uid: 'chicken', name: 'Chicken', icon: '🍗', diet_class: 'nonveg', sort: 7 },
|
||||
{ uid: 'fish', name: 'Fish', icon: '🐟', diet_class: 'nonveg', sort: 8 },
|
||||
{ uid: 'prawns', name: 'Prawns', icon: '🍤', diet_class: 'nonveg', sort: 9 },
|
||||
{ uid: 'pork', name: 'Pork', icon: '🥓', diet_class: 'nonveg', sort: 10 },
|
||||
{ uid: 'mutton', name: 'Mutton', icon: '🍖', diet_class: 'nonveg', sort: 11 },
|
||||
]
|
||||
|
||||
const CAT_CODES = {
|
||||
'brew-bites': 'BRB',
|
||||
'sharing-plates': 'SHP',
|
||||
@@ -49,7 +71,7 @@ const CAT_CODES = {
|
||||
let sortCounter = 0
|
||||
const skuCounters = {}
|
||||
|
||||
function item(category, name, price, { variant = '', desc = '', diet = 'mixed', tag = '', pairing = '' } = {}) {
|
||||
function item(category, name, price, { variant = '', desc = '', ing = [], tag = '', pairing = '' } = {}) {
|
||||
sortCounter += 1
|
||||
skuCounters[category] = (skuCounters[category] ?? 0) + 1
|
||||
const slugSource = variant ? `${name} ${variant}` : name
|
||||
@@ -64,7 +86,7 @@ function item(category, name, price, { variant = '', desc = '', diet = 'mixed',
|
||||
variant,
|
||||
description: desc,
|
||||
price,
|
||||
diet,
|
||||
ingredients: ing,
|
||||
pairing,
|
||||
tag,
|
||||
image: '',
|
||||
@@ -78,687 +100,678 @@ function item(category, name, price, { variant = '', desc = '', diet = 'mixed',
|
||||
export const MENU_ITEMS = [
|
||||
// ---------------------------------------------------------------- Brew Bites
|
||||
item('brew-bites', 'Chana Chaat', 399, {
|
||||
diet: 'veg',
|
||||
desc: 'Cooked white chickpeas tossed with onion, tomato, herbs, sweet & spicy chutney & aromatic spices',
|
||||
}),
|
||||
item('brew-bites', 'French Fries', 389, {
|
||||
diet: 'veg',
|
||||
tag: 'Classic / Gunpowder / Peri-Peri',
|
||||
}),
|
||||
item('brew-bites', 'Garlic Bread', 239, { variant: 'Plain', diet: 'veg', desc: 'House bake' }),
|
||||
item('brew-bites', 'Garlic Bread', 399, { variant: 'With Cheese', diet: 'veg', desc: 'House bake' }),
|
||||
item('brew-bites', 'Onion Rings', 419, { diet: 'veg', desc: 'Deep fried onion rings + thousand island' }),
|
||||
item('brew-bites', 'Garlic Bread', 239, { variant: 'Plain', desc: 'House bake', ing: ['gluten', 'dairy'] }),
|
||||
item('brew-bites', 'Garlic Bread', 399, { variant: 'With Cheese', desc: 'House bake', ing: ['gluten', 'dairy'] }),
|
||||
item('brew-bites', 'Onion Rings', 419, { desc: 'Deep fried onion rings + thousand island', ing: ['gluten', 'dairy'] }),
|
||||
item('brew-bites', 'Peanut Papad Masala', 389, {
|
||||
diet: 'veg',
|
||||
desc: 'Roasted peanuts tossed with onion, tomato, lemon, fresh coriander & aromatic spices',
|
||||
ing: ['nuts'],
|
||||
}),
|
||||
item('brew-bites', 'Edamame', 389, {
|
||||
diet: 'veg',
|
||||
tag: 'Steamed / Spicy',
|
||||
desc: 'Edamame in the pod steamed & salted / tempered with garlic & chili',
|
||||
ing: ['soy'],
|
||||
}),
|
||||
item('brew-bites', 'Chicken & Cheese Bites', 459, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken minced and cheese mix, fried to perfection + chipotle dip',
|
||||
ing: ['chicken', 'dairy', 'gluten'],
|
||||
}),
|
||||
|
||||
// ------------------------------------------------------------ Sharing Plates
|
||||
item('sharing-plates', 'Hummus Pita Platter', 449, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Classic, roasted bell pepper & black beans-cumin hummus, pita, sesame naan & za’atar crostini + arabic pickle',
|
||||
ing: ['gluten'],
|
||||
}),
|
||||
item('sharing-plates', 'Hummus Pita Platter', 549, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Classic, roasted bell pepper & black beans-cumin hummus, pita, sesame naan & za’atar crostini + arabic pickle',
|
||||
ing: ['gluten', 'chicken'],
|
||||
}),
|
||||
item('sharing-plates', 'Ultimate Nachos', 599, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Corn tortilla, beans sauce, pico-de-gallo, cheese sauce, tomato salsa & sour cream',
|
||||
ing: ['dairy', 'gluten'],
|
||||
}),
|
||||
item('sharing-plates', 'Ultimate Nachos', 699, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Corn tortilla, beans sauce, pico-de-gallo, cheese sauce, tomato salsa & sour cream',
|
||||
ing: ['dairy', 'gluten', 'chicken'],
|
||||
}),
|
||||
|
||||
// ------------------------------------------------------------------- Salads
|
||||
item('salads', 'Avocado & Egg Salad', 509, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Mixed greens, green beans, cherry tomato, olives, pumpkin seeds + malta vinaigrette',
|
||||
ing: ['egg'],
|
||||
}),
|
||||
item('salads', 'Crispy Lotus Stem & Chickpea Salad', 429, {
|
||||
diet: 'veg',
|
||||
desc: 'Lettuce, bell peppers, corns, chickpeas, crispy lotus stem + citrus vinaigrette',
|
||||
}),
|
||||
item('salads', 'Caesar Salad', 449, {
|
||||
tag: 'Veg / Chicken',
|
||||
desc: 'Iceberg, romaine, parmesan shavings, croutons + veg caesar dressing',
|
||||
ing: ['dairy', 'egg', 'gluten', 'chicken'],
|
||||
}),
|
||||
item('salads', 'Chicken Tikka Niçoise Salad', 499, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Mixed greens, pulled chicken tikka, boiled egg, potato cubes, green beans, olives + lemon vinaigrette',
|
||||
ing: ['chicken', 'egg'],
|
||||
}),
|
||||
item('salads', 'Quinoa Health Freak Salad', 499, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Quinoa, lettuce, cucumber, cherry tomato, olives, broccoli + apple cider dressing',
|
||||
}),
|
||||
item('salads', 'Quinoa Health Freak Salad', 529, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Quinoa, lettuce, cucumber, cherry tomato, olives, broccoli + apple cider dressing',
|
||||
ing: ['chicken'],
|
||||
}),
|
||||
item('salads', 'Roasted Beetroot & Walnut Salad', 449, {
|
||||
diet: 'veg',
|
||||
desc: 'Mixed lettuce, roasted beet, broccoli, orange segments, cherry tomatoes & feta + balsamic dressing',
|
||||
ing: ['nuts', 'dairy'],
|
||||
}),
|
||||
item('salads', 'Warm Vegetable Salad', 469, {
|
||||
diet: 'veg',
|
||||
desc: 'Warm exotic vegetables tossed with mustard dressing, topped with pumpkin seeds & roasted almond',
|
||||
ing: ['nuts'],
|
||||
}),
|
||||
|
||||
// ----------------------------------------------------------------- Platters
|
||||
item('platters', 'Chelo Kebab Platter', 1069, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Basil chicken seekh, za’atar mutton seekh, chicken shish taouk, sumac chicken breast, saffron rice + tzatziki',
|
||||
ing: ['chicken', 'mutton', 'dairy'],
|
||||
}),
|
||||
item('platters', 'Chicken Tikka Platter', 1159, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Herb-pepper, malai, parmesan chicken, angara, lehsuni',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('platters', 'Mezze Platter', 899, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Pan seared cottage cheese, falafel, spinach-ricotta roll, tabbouleh, pita bread, arabic pickle + hummus, labneh, chilli dip',
|
||||
ing: ['dairy', 'gluten'],
|
||||
}),
|
||||
item('platters', 'Mezze Platter', 1159, {
|
||||
variant: 'Non-Veg',
|
||||
diet: 'nonveg',
|
||||
desc: 'Cajun fish, peri-peri chicken, lamb roll, chicken kafta, arabic pickle, pita bread + hummus, labneh, chilli dip',
|
||||
ing: ['fish', 'chicken', 'mutton', 'dairy', 'gluten'],
|
||||
}),
|
||||
item('platters', 'Tandoori Veg Platter', 999, {
|
||||
diet: 'veg',
|
||||
desc: 'Achari paneer tikka, hari mirch paneer tikka, tandoori khumb, roasted pineapple, tandoori soya chaap, quinoa veg seekh, sprouted moong kebab',
|
||||
ing: ['dairy', 'soy', 'mushroom'],
|
||||
}),
|
||||
item('platters', 'Seafood Fritters Platter', 1299, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Batter fried prawns, ajwain fish fry, fish fingers, mixed seafood fritters + tartar sauce, mint mayo',
|
||||
ing: ['prawns', 'fish', 'egg', 'gluten'],
|
||||
}),
|
||||
item('platters', 'Tandoori Meat Platter', 1299, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Tandoori prawns, tandoori fish tikka, mutton seekh, tandoori chicken, angara chicken tikka, parmesan chicken tikka, chicken seekh',
|
||||
ing: ['prawns', 'fish', 'mutton', 'chicken', 'dairy'],
|
||||
}),
|
||||
item('platters', 'Sizzler', 699, {
|
||||
variant: 'Cottage Cheese',
|
||||
diet: 'veg',
|
||||
desc: 'Choose your starch (fried rice / noodles) & your sauce (schezwan / sweet n sour); served with soya sesame vegetables, grilled pineapple slice & fries',
|
||||
ing: ['dairy', 'soy', 'gluten'],
|
||||
}),
|
||||
item('platters', 'Sizzler', 699, {
|
||||
variant: 'Manchurian',
|
||||
diet: 'veg',
|
||||
desc: 'Choose your starch (fried rice / noodles) & your sauce (schezwan / sweet n sour); served with soya sesame vegetables, grilled pineapple slice & fries',
|
||||
ing: ['soy', 'gluten'],
|
||||
}),
|
||||
item('platters', 'Sizzler', 799, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Choose your starch (fried rice / noodles) & your sauce (schezwan / sweet n sour); served with soya sesame vegetables, grilled pineapple slice & fries',
|
||||
ing: ['chicken', 'soy', 'gluten'],
|
||||
}),
|
||||
|
||||
// ------------------------------------------------- International Appetizers
|
||||
item('international-appetizers', 'Apple & Avocado Salsa', 439, {
|
||||
diet: 'veg',
|
||||
desc: 'Granny smith apple, khakhra crisp and melba toast',
|
||||
ing: ['gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Mushroom Pepper Fry', 549, {
|
||||
diet: 'veg',
|
||||
desc: 'Mushroom cooked with black pepper fry masala + Malabari parotta',
|
||||
ing: ['mushroom', 'gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Corn Salt N Pepper', 519, {
|
||||
diet: 'veg',
|
||||
desc: 'Crispy fried corn, onions, spring onions',
|
||||
}),
|
||||
item('international-appetizers', 'Chilli Paneer / Chilli Mushroom', 549, {
|
||||
diet: 'veg',
|
||||
tag: 'Paneer / Mushroom',
|
||||
desc: 'Crispy fried cubes, onion, capsicum, bell peppers + chilli paste',
|
||||
ing: ['dairy', 'mushroom', 'soy'],
|
||||
}),
|
||||
item('international-appetizers', 'Cottage Cheese Quesadilla', 579, {
|
||||
diet: 'veg',
|
||||
desc: 'Flour tortilla, mix cheese, beans + tomato salsa, sour cream',
|
||||
ing: ['dairy', 'gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Falafel', 439, {
|
||||
diet: 'veg',
|
||||
desc: 'Arabic pickle, chickpea patties + hummus & pita',
|
||||
ing: ['gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Honey Chilly Cauliflower / Potato', 449, {
|
||||
diet: 'veg',
|
||||
tag: 'Cauliflower / Potato',
|
||||
desc: 'Crispy fried cauliflower/potato, sesame seeds, honey chili sauce',
|
||||
ing: ['gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Korean Fried Paneer', 549, {
|
||||
diet: 'veg',
|
||||
desc: 'Crispy fried paneer tossed in umami Korean sauce',
|
||||
ing: ['dairy', 'soy', 'gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Peri-Peri Quinoa Popcorn', 449, {
|
||||
diet: 'veg',
|
||||
desc: 'Paneer cubes, quinoa crusted + peri peri dust and roasted garlic aioli',
|
||||
ing: ['dairy', 'egg'],
|
||||
}),
|
||||
item('international-appetizers', 'Exotic Vegetables', 439, {
|
||||
diet: 'veg',
|
||||
desc: 'Stir fry vegetables with garlic and butter',
|
||||
ing: ['dairy', 'soy'],
|
||||
}),
|
||||
item('international-appetizers', 'Thai Chilli Crispy Lotus Stems', 479, {
|
||||
diet: 'veg',
|
||||
desc: 'Crispy fried lotus stems in chilli sauce, spring onion & roasted sesame seeds',
|
||||
}),
|
||||
item('international-appetizers', 'Veg Manchurian', 449, {
|
||||
diet: 'veg',
|
||||
desc: 'Fried vegetable balls in sweet & sour, hot manchurian sauce',
|
||||
ing: ['soy', 'gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Veg Cigar Roll', 449, {
|
||||
diet: 'veg',
|
||||
desc: 'Crispy fried cigar rolls stuffed with cheese & fresh vegetables, pickled salad & spicy remoulade',
|
||||
ing: ['dairy', 'gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Boneless Chicken Wings', 629, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Juicy crispy boneless chicken breast + classic hot sauce, ranch dip',
|
||||
ing: ['chicken', 'gluten', 'dairy'],
|
||||
}),
|
||||
item('international-appetizers', 'BBQ Pork Ribs', 899, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Tender slow cooked BBQ pork ribs served with crispy french fries',
|
||||
ing: ['pork'],
|
||||
}),
|
||||
item('international-appetizers', 'Chicken Quesadilla', 719, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Flour tortillas filled with chicken & cheese, mexican rice + pico de gallo, sour cream',
|
||||
ing: ['chicken', 'dairy', 'gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Chilli Chicken', 639, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Crispy fried boneless chicken, onion, bell peppers + chilli paste',
|
||||
ing: ['chicken', 'soy'],
|
||||
}),
|
||||
item('international-appetizers', 'Chicken Wings', 599, {
|
||||
diet: 'nonveg',
|
||||
tag: 'BBQ / Hot Sauce / Peri-Peri / Grandma Style',
|
||||
desc: 'Crispy fried to perfection',
|
||||
ing: ['chicken', 'gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Chilly Garlic Prawns', 889, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Spicy prawns tossed in hot garlic sauce',
|
||||
ing: ['prawns', 'soy'],
|
||||
}),
|
||||
item('international-appetizers', 'Fish and Chips', 799, {
|
||||
variant: 'Basa',
|
||||
diet: 'nonveg',
|
||||
desc: 'Crispy battered fish served with golden fries + egg tartar sauce, ponzu dip',
|
||||
ing: ['fish', 'gluten', 'egg'],
|
||||
}),
|
||||
item('international-appetizers', 'Fish and Chips', 949, {
|
||||
variant: 'Sole',
|
||||
diet: 'nonveg',
|
||||
desc: 'Crispy battered fish served with golden fries + egg tartar sauce, ponzu dip',
|
||||
ing: ['fish', 'gluten', 'egg'],
|
||||
}),
|
||||
item('international-appetizers', 'Korean Fried Chicken', 639, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Crispy fried chicken tossed in umami Korean sauce',
|
||||
ing: ['chicken', 'soy', 'gluten'],
|
||||
}),
|
||||
item('international-appetizers', 'Moroccan Grilled Chicken', 659, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Arabic spice, hung curd, served with grilled veggies + creamy labneh',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('international-appetizers', 'Kaffir Lime-Coconut Fish Fillet', 799, {
|
||||
variant: 'Basa',
|
||||
diet: 'nonveg',
|
||||
desc: 'Thai flavour infused fish with spicy coconut curry',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('international-appetizers', 'Kaffir Lime-Coconut Fish Fillet', 949, {
|
||||
variant: 'Sole',
|
||||
diet: 'nonveg',
|
||||
desc: 'Thai flavour infused fish with spicy coconut curry',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('international-appetizers', 'Schezwan Chicken Lollipop', 599, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Crispy oriental style chicken wings tossed in fiery schezwan sauce',
|
||||
ing: ['chicken', 'soy'],
|
||||
}),
|
||||
item('international-appetizers', 'Spicy Chicken Strips', 599, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Spicy strips + sweet chilli sauce',
|
||||
ing: ['chicken', 'gluten'],
|
||||
}),
|
||||
|
||||
// -------------------------------------------------------- Indian Appetizers
|
||||
item('indian-appetizers', 'Quinoa Seekh Kebab', 429, {
|
||||
diet: 'veg',
|
||||
desc: 'Minced vegetables, paneer & quinoa seekh kebab + mint sauce',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Sprouted Moong Kebab', 429, {
|
||||
diet: 'veg',
|
||||
desc: 'Green sprouted moong, fresh coriander, spices & shallow fry + mint sauce',
|
||||
}),
|
||||
item('indian-appetizers', 'Dahi Kebab', 449, {
|
||||
diet: 'veg',
|
||||
desc: 'Hung curd, onion, bell pepper, coriander seeds, seasoning',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Prune Stuffed Paneer Tikka', 559, {
|
||||
diet: 'veg',
|
||||
desc: 'Khata meeta prunes stuffed paneer, marinated with tandoori masala + mint sauce',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Molten Beetroot & Peanut Kebab', 449, {
|
||||
diet: 'veg',
|
||||
desc: 'Crumb fried beetroot kebab stuffed with cheese + scallion cream',
|
||||
ing: ['nuts', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Paneer Tikka', 549, {
|
||||
diet: 'veg',
|
||||
tag: 'Malai / Hari Mirch / Angara',
|
||||
desc: 'Paneer marinated with spices, cooked in tandoor, served hot + mint sauce',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Sweet Potato & Goat Cheese Tikki', 449, {
|
||||
diet: 'veg',
|
||||
desc: 'Cranberry-sesame chutney, red chilli-green apple salsa',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Roasted Pineapple', 449, {
|
||||
diet: 'veg',
|
||||
desc: 'Roasted in clay oven with Indian spices + mint sauce',
|
||||
}),
|
||||
item('indian-appetizers', 'Tandoori Khumb', 529, {
|
||||
diet: 'veg',
|
||||
desc: 'Spicy mushrooms + mint sauce',
|
||||
ing: ['mushroom', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Tandoori Soya Chaap', 459, {
|
||||
diet: 'veg',
|
||||
tag: 'Malai / Angara',
|
||||
desc: 'Soya chaap cooked in clay oven + mint sauce',
|
||||
ing: ['soy', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Maharashtrian Thecha Paneer', 549, {
|
||||
diet: 'veg',
|
||||
desc: 'Green chili thecha tossed paneer cubes + Malabari paratha',
|
||||
ing: ['dairy', 'gluten'],
|
||||
}),
|
||||
item('indian-appetizers', 'Amritsari Fish Fry', 729, {
|
||||
variant: 'Basa',
|
||||
diet: 'nonveg',
|
||||
desc: 'Gram flour batter fried fish + mint chutney',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('indian-appetizers', 'Amritsari Fish Fry', 869, {
|
||||
variant: 'Sole',
|
||||
diet: 'nonveg',
|
||||
desc: 'Gram flour batter fried fish + mint chutney',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('indian-appetizers', 'Chicken Tikka', 639, {
|
||||
diet: 'nonveg',
|
||||
tag: 'Malai / Parmesan / Lehsuni / Angara / Herb-Pepper',
|
||||
desc: 'Marinated chicken, cooked in tandoor — choose your flavour',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Chicken Seekh', 549, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Marinated minced chicken, Indian herbs, spices + mint sauce',
|
||||
ing: ['chicken'],
|
||||
}),
|
||||
item('indian-appetizers', 'Fish Tikka', 729, {
|
||||
variant: 'Basa',
|
||||
diet: 'nonveg',
|
||||
tag: 'Angara / Kasundi',
|
||||
desc: 'Marinated fish cooked in clay oven + mint sauce',
|
||||
ing: ['fish', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Fish Tikka', 869, {
|
||||
variant: 'Sole',
|
||||
diet: 'nonveg',
|
||||
tag: 'Angara / Kasundi',
|
||||
desc: 'Marinated fish cooked in clay oven + mint sauce',
|
||||
ing: ['fish', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Grilled Tawa Fish', 729, {
|
||||
variant: 'Basa',
|
||||
diet: 'nonveg',
|
||||
desc: 'Fish marinated in Indian spices, pan grilled to perfection + mint sauce',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('indian-appetizers', 'Grilled Tawa Fish', 869, {
|
||||
variant: 'Sole',
|
||||
diet: 'nonveg',
|
||||
desc: 'Fish marinated in Indian spices, pan grilled to perfection + mint sauce',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('indian-appetizers', 'Mutton Chapli Kebab', 759, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Minced mutton, chapli masala, cooked to perfection + rogan josh jus',
|
||||
ing: ['mutton'],
|
||||
}),
|
||||
item('indian-appetizers', 'Mutton Seekh Kebab', 729, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Marinated minced lamb seasoned with Indian herbs & spices',
|
||||
ing: ['mutton'],
|
||||
}),
|
||||
item('indian-appetizers', 'Tandoori Chicken', 559, {
|
||||
variant: 'Half',
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken on the bone in cultured yogurt and spices',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Tandoori Chicken', 889, {
|
||||
variant: 'Full',
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken on the bone in cultured yogurt and spices',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Tandoori Wings', 579, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken wings in cultured yogurt and spices',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('indian-appetizers', 'Prawns Masala', 949, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Spicy onion, tomato masala with curry leaves & mustard, served with uttapam',
|
||||
ing: ['prawns', 'gluten'],
|
||||
}),
|
||||
item('indian-appetizers', 'Tawa Masala', 549, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Punjabi style chicken on bone, tawa masala & ground spices',
|
||||
ing: ['chicken'],
|
||||
}),
|
||||
item('indian-appetizers', 'Tawa Masala', 779, {
|
||||
variant: 'Mutton',
|
||||
diet: 'nonveg',
|
||||
desc: 'Punjabi style mutton on bone, tawa masala & ground spices',
|
||||
ing: ['mutton'],
|
||||
}),
|
||||
item('indian-appetizers', 'Nimbu Hari Mirch ki Tangari', 579, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken drumstick, spicy hari mirch nimbu marinated, cooked to perfection + mint sauce',
|
||||
ing: ['chicken'],
|
||||
}),
|
||||
|
||||
// -------------------------------------------------------------- Main Course
|
||||
item('main-course', 'Cottage Cheese Steak', 629, {
|
||||
diet: 'veg',
|
||||
desc: 'Herb quinoa, creamy spinach-corn, sautéed vegetables + roasted pepper coulis',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('main-course', 'Cajun Grilled Fish', 769, {
|
||||
variant: 'Basa',
|
||||
diet: 'nonveg',
|
||||
desc: 'Quinoa, sautéed vegetables, guacamole',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('main-course', 'Cajun Grilled Fish', 899, {
|
||||
variant: 'Sole',
|
||||
diet: 'nonveg',
|
||||
desc: 'Quinoa, sautéed vegetables, guacamole',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('main-course', 'Roasted Garlic & Basil Chicken Thigh', 699, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Garlic & basil chicken thigh, brown onion pilaf, butter broccoli & spicy pepper coulis',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('main-course', 'Grilled Chicken Breast', 699, {
|
||||
diet: 'nonveg',
|
||||
tag: 'Classic Chicken Jus / Hot Peri Peri',
|
||||
desc: 'Mash potato, sautéed vegetables',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('main-course', 'Penne Arrabiata', 589, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Pasta with exotic vegetables, basil, chilli flakes, chunky tomatoes + garlic bread',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('main-course', 'Penne Arrabiata', 639, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Pasta with exotic vegetables, basil, chilli flakes, chunky tomatoes + garlic bread',
|
||||
ing: ['gluten', 'dairy', 'chicken'],
|
||||
}),
|
||||
item('main-course', 'Penne Alfredo', 599, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'With exotic vegetables, creamy cheesy sauce + garlic bread',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('main-course', 'Penne Alfredo', 649, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'With exotic vegetables, creamy cheesy sauce + garlic bread',
|
||||
ing: ['gluten', 'dairy', 'chicken'],
|
||||
}),
|
||||
item('main-course', 'Penne Salsa Rosa', 599, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Penne in mix sauce, exotic vegetables + garlic bread',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('main-course', 'Penne Salsa Rosa', 649, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Penne in mix sauce, exotic vegetables + garlic bread',
|
||||
ing: ['gluten', 'dairy', 'chicken'],
|
||||
}),
|
||||
item('main-course', 'Pan Seared Salmon', 1259, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Creamy mashed potato, grilled vegetables + lemon caper sauce',
|
||||
ing: ['fish', 'dairy'],
|
||||
}),
|
||||
item('main-course', 'Spaghetti Aglio e Olio', 549, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Olive oil, garlic, olives, chili flakes + garlic bread',
|
||||
ing: ['gluten'],
|
||||
}),
|
||||
item('main-course', 'Spaghetti Aglio e Olio', 599, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Olive oil, garlic, olives, chili flakes + garlic bread',
|
||||
ing: ['gluten', 'chicken'],
|
||||
}),
|
||||
item('main-course', 'Chow Mein', 399, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Wok tossed noodles with soy, vinegar & chili sauce',
|
||||
ing: ['gluten', 'soy'],
|
||||
}),
|
||||
item('main-course', 'Chow Mein', 429, {
|
||||
variant: 'Egg',
|
||||
diet: 'nonveg',
|
||||
desc: 'Wok tossed noodles with soy, vinegar & chili sauce',
|
||||
ing: ['gluten', 'soy', 'egg'],
|
||||
}),
|
||||
item('main-course', 'Chow Mein', 479, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Wok tossed noodles with soy, vinegar & chili sauce',
|
||||
ing: ['gluten', 'soy', 'chicken'],
|
||||
}),
|
||||
item('main-course', 'Fried Rice', 399, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
desc: 'Wok tossed rice with soy, vinegar & chili sauce',
|
||||
ing: ['soy'],
|
||||
}),
|
||||
item('main-course', 'Fried Rice', 429, {
|
||||
variant: 'Egg',
|
||||
diet: 'nonveg',
|
||||
desc: 'Wok tossed rice with soy, vinegar & chili sauce',
|
||||
ing: ['soy', 'egg'],
|
||||
}),
|
||||
item('main-course', 'Fried Rice', 479, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Wok tossed rice with soy, vinegar & chili sauce',
|
||||
ing: ['soy', 'chicken'],
|
||||
}),
|
||||
item('main-course', 'Thai Curry', 579, {
|
||||
variant: 'Veg',
|
||||
diet: 'veg',
|
||||
tag: 'Green / Red',
|
||||
desc: 'Veggies cooked in creamy coconut gravy, curry paste + steamed rice',
|
||||
}),
|
||||
item('main-course', 'Thai Curry', 629, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
tag: 'Green / Red',
|
||||
desc: 'Veggies cooked in creamy coconut gravy, curry paste + steamed rice',
|
||||
ing: ['chicken'],
|
||||
}),
|
||||
item('main-course', 'Thai Curry', 659, {
|
||||
variant: 'Prawns',
|
||||
diet: 'nonveg',
|
||||
tag: 'Green / Red',
|
||||
desc: 'Veggies cooked in creamy coconut gravy, curry paste + steamed rice',
|
||||
ing: ['prawns'],
|
||||
}),
|
||||
item('main-course', 'Chili Garlic Noodles', 429, {
|
||||
diet: 'veg',
|
||||
desc: 'Noodles tossed with authentic chili-garlic sauce, spring onion and soya',
|
||||
ing: ['gluten', 'soy'],
|
||||
}),
|
||||
|
||||
// ------------------------------------------------------------------ Curries
|
||||
item('curries', 'Dal Tadka / Palak Dal / Lasooni Dal', 399, {
|
||||
diet: 'veg',
|
||||
desc: 'Mix of moong & masoor dal, as you wish',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('curries', 'Dal Makhani', 479, {
|
||||
diet: 'veg',
|
||||
desc: 'Overnight slow cooked black urad dal, tempered with kasoori methi, cream & butter',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('curries', 'Kasoori Subz Milani', 519, {
|
||||
diet: 'veg',
|
||||
desc: 'Melange of seasonal vegetables tossed in onion masala, dried fenugreek',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('curries', 'Kadhai / Makhani Paneer', 599, {
|
||||
diet: 'veg',
|
||||
tag: 'Kadhai / Makhani',
|
||||
desc: 'Cottage cheese, capsicum, onion & kadhai masala / creamy tomato gravy',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('curries', 'Methi Palak Paneer', 569, {
|
||||
diet: 'veg',
|
||||
desc: 'Cubes of cottage cheese, spinach & fenugreek',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('curries', 'Paneer Lababdar', 619, {
|
||||
diet: 'veg',
|
||||
desc: 'Cubes of cottage cheese, bell pepper, onions & capsicum',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('curries', 'Mushroom Hara Pyaz', 579, {
|
||||
diet: 'veg',
|
||||
desc: 'Mushroom & hara pyaz tossed in chopped masala',
|
||||
ing: ['mushroom'],
|
||||
}),
|
||||
item('curries', 'Punjabi Chana Masala', 459, {
|
||||
diet: 'veg',
|
||||
desc: 'White chickpeas with fragrant herbs & spices',
|
||||
}),
|
||||
item('curries', 'Butter Chicken', 779, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken on bone + creamy tomato gravy',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('curries', 'Egg Curry', 519, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Hard boiled eggs in Indian gravy',
|
||||
ing: ['egg'],
|
||||
}),
|
||||
item('curries', 'Punjabi Fish Curry', 759, {
|
||||
variant: 'Basa',
|
||||
diet: 'nonveg',
|
||||
desc: 'Choice of protein cooked in spicy tangy, onion tomato curry',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('curries', 'Punjabi Fish Curry', 859, {
|
||||
variant: 'Sole',
|
||||
diet: 'nonveg',
|
||||
desc: 'Choice of protein cooked in spicy tangy, onion tomato curry',
|
||||
ing: ['fish'],
|
||||
}),
|
||||
item('curries', 'Punjabi Fish Curry', 899, {
|
||||
variant: 'Prawns',
|
||||
diet: 'nonveg',
|
||||
desc: 'Choice of protein cooked in spicy tangy, onion tomato curry',
|
||||
ing: ['prawns'],
|
||||
}),
|
||||
item('curries', 'Home Style Chicken Curry', 659, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken on bone + home style gravy',
|
||||
ing: ['chicken'],
|
||||
}),
|
||||
item('curries', 'Kadhai Chicken', 779, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken on bone + kadhai masala',
|
||||
ing: ['chicken'],
|
||||
}),
|
||||
item('curries', 'Mutton Rogan Josh', 829, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Tender mutton on the bone, Kashmiri style',
|
||||
ing: ['mutton'],
|
||||
}),
|
||||
item('curries', 'Kulcha with Curry', 299, {
|
||||
variant: 'Paneer',
|
||||
diet: 'veg',
|
||||
desc: 'Fresh kulcha served with your choice of curry',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('curries', 'Kulcha with Curry', 499, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Fresh kulcha served with your choice of curry',
|
||||
ing: ['gluten', 'chicken'],
|
||||
}),
|
||||
item('curries', 'Kulcha with Curry', 599, {
|
||||
variant: 'Mutton',
|
||||
diet: 'nonveg',
|
||||
desc: 'Fresh kulcha served with your choice of curry',
|
||||
ing: ['gluten', 'mutton'],
|
||||
}),
|
||||
|
||||
// --------------------------------------------------- Biryanis, Rice & Breads
|
||||
item('biryanis-rice-breads', 'Biryani', 779, {
|
||||
variant: 'Chicken',
|
||||
diet: 'nonveg',
|
||||
desc: 'Aromatic basmati rice cooked in saffron & spices + mix raita',
|
||||
ing: ['chicken', 'dairy'],
|
||||
}),
|
||||
item('biryanis-rice-breads', 'Biryani', 639, {
|
||||
variant: 'Egg',
|
||||
diet: 'nonveg',
|
||||
desc: 'Aromatic basmati rice cooked in saffron & spices + mix raita',
|
||||
ing: ['egg', 'dairy'],
|
||||
}),
|
||||
item('biryanis-rice-breads', 'Biryani', 889, {
|
||||
variant: 'Mutton',
|
||||
diet: 'nonveg',
|
||||
desc: 'Aromatic basmati rice cooked in saffron & spices + mix raita',
|
||||
ing: ['mutton', 'dairy'],
|
||||
}),
|
||||
item('biryanis-rice-breads', 'Biryani', 599, {
|
||||
variant: 'Vegetable',
|
||||
diet: 'veg',
|
||||
desc: 'Aromatic basmati rice cooked in saffron & spices + mix raita',
|
||||
ing: ['dairy'],
|
||||
}),
|
||||
item('biryanis-rice-breads', 'Jeera Rice', 269, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Steamed Rice', 239, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Dhungari Burani Raita', 199, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Masala Boondi Raita', 189, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Onion, Tomato, Cucumber Raita', 189, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Pudina Raita', 189, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Butter Roti', 79, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Butter Naan', 99, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Garlic / Coriander Naan', 109, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Kachi Haldi Naan', 109, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Laccha / Pudina Parantha', 99, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Missi Roti', 99, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Onion Kulcha', 109, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Paneer Kulcha', 179, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Tandoori Naan', 89, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Tandoori Roti', 69, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Khamiri Roti', 79, { diet: 'veg' }),
|
||||
item('biryanis-rice-breads', 'Jeera Rice', 269, {}),
|
||||
item('biryanis-rice-breads', 'Steamed Rice', 239, {}),
|
||||
item('biryanis-rice-breads', 'Dhungari Burani Raita', 199, { ing: ['dairy'] }),
|
||||
item('biryanis-rice-breads', 'Masala Boondi Raita', 189, { ing: ['dairy'] }),
|
||||
item('biryanis-rice-breads', 'Onion, Tomato, Cucumber Raita', 189, { ing: ['dairy'] }),
|
||||
item('biryanis-rice-breads', 'Pudina Raita', 189, { ing: ['dairy'] }),
|
||||
item('biryanis-rice-breads', 'Butter Roti', 79, { ing: ['gluten', 'dairy'] }),
|
||||
item('biryanis-rice-breads', 'Butter Naan', 99, { ing: ['gluten', 'dairy'] }),
|
||||
item('biryanis-rice-breads', 'Garlic / Coriander Naan', 109, { ing: ['gluten', 'dairy'] }),
|
||||
item('biryanis-rice-breads', 'Kachi Haldi Naan', 109, { ing: ['gluten', 'dairy'] }),
|
||||
item('biryanis-rice-breads', 'Laccha / Pudina Parantha', 99, { ing: ['gluten', 'dairy'] }),
|
||||
item('biryanis-rice-breads', 'Missi Roti', 99, { ing: ['gluten'] }),
|
||||
item('biryanis-rice-breads', 'Onion Kulcha', 109, { ing: ['gluten', 'dairy'] }),
|
||||
item('biryanis-rice-breads', 'Paneer Kulcha', 179, { ing: ['gluten', 'dairy'] }),
|
||||
item('biryanis-rice-breads', 'Tandoori Naan', 89, { ing: ['gluten', 'dairy'] }),
|
||||
item('biryanis-rice-breads', 'Tandoori Roti', 69, { ing: ['gluten'] }),
|
||||
item('biryanis-rice-breads', 'Khamiri Roti', 79, { ing: ['gluten'] }),
|
||||
|
||||
// ----------------------------------------------------------------- Desserts
|
||||
item('desserts', 'Baked Cheesecake', 419, {
|
||||
diet: 'veg',
|
||||
desc: 'Fresh berries compote',
|
||||
ing: ['dairy', 'gluten', 'egg'],
|
||||
}),
|
||||
item('desserts', 'Churros', 299, {
|
||||
diet: 'veg',
|
||||
desc: 'Chocolate sauce, caramel sauce & whipped cream',
|
||||
ing: ['gluten', 'egg', 'dairy'],
|
||||
}),
|
||||
item('desserts', 'Dark Chocolate Brownie with Ice Cream', 339, {
|
||||
diet: 'veg',
|
||||
desc: 'Brownie topped with vanilla ice cream + chocolate sauce',
|
||||
ing: ['gluten', 'egg', 'dairy'],
|
||||
}),
|
||||
|
||||
// ------------------------------------------------------------------- Pizzas
|
||||
item('pizzas', 'Burnt Garlic Mushroom Pizza', 589, {
|
||||
diet: 'veg',
|
||||
desc: 'Sautéed mushrooms, burnt garlic, onions',
|
||||
ing: ['gluten', 'dairy', 'mushroom'],
|
||||
}),
|
||||
item('pizzas', 'Garden Fresh Pizza', 579, {
|
||||
diet: 'veg',
|
||||
desc: 'American corn, onion, tomato, capsicum & jalapeno',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('pizzas', 'Exotic Pizza', 599, {
|
||||
diet: 'veg',
|
||||
desc: 'Broccoli, zucchini, bell pepper, olives & baby corn',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('pizzas', 'Margherita Pizza', 559, {
|
||||
diet: 'veg',
|
||||
desc: 'Mozzarella cheese & fresh basil',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('pizzas', 'Paneer Tikka Pizza', 599, {
|
||||
diet: 'veg',
|
||||
desc: 'Paneer tikka, onion, tomato, capsicum',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('pizzas', 'Sundried-Tomato & Olives Pizza', 589, {
|
||||
diet: 'veg',
|
||||
desc: 'Homemade sundried tomato, caper & fresh basil',
|
||||
ing: ['gluten', 'dairy'],
|
||||
}),
|
||||
item('pizzas', 'BBQ Pulled Chicken Pizza', 719, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Slow cooked pulled chicken, BBQ sauce & jalapeno',
|
||||
ing: ['gluten', 'dairy', 'chicken'],
|
||||
}),
|
||||
item('pizzas', 'Chicken Overload Pizza', 729, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken tikka, BBQ chicken, herb chicken, onion',
|
||||
ing: ['gluten', 'dairy', 'chicken'],
|
||||
}),
|
||||
item('pizzas', 'Chicken Tikka Pizza', 719, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Chicken tikka, onion, tomato & capsicum',
|
||||
ing: ['gluten', 'dairy', 'chicken'],
|
||||
}),
|
||||
item('pizzas', 'Meat Lover Pizza', 729, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Mutton seekh, tikka chicken & chicken salami',
|
||||
ing: ['gluten', 'dairy', 'chicken', 'mutton'],
|
||||
}),
|
||||
item('pizzas', 'Pepperoni Pizza', 769, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Pork pepperoni, jalapeno, olives & fresh basil',
|
||||
ing: ['gluten', 'dairy', 'pork'],
|
||||
}),
|
||||
item('pizzas', 'Peri-Peri Chicken Pizza', 729, {
|
||||
diet: 'nonveg',
|
||||
desc: 'Peri peri marinated chicken, olives & pickled onion',
|
||||
ing: ['gluten', 'dairy', 'chicken'],
|
||||
}),
|
||||
]
|
||||
|
||||
+4
-2
@@ -4,6 +4,7 @@ import {
|
||||
createReservationRecord,
|
||||
fetchBrews,
|
||||
fetchExperiences,
|
||||
fetchIngredients,
|
||||
fetchMenuCategories,
|
||||
fetchMenuItems,
|
||||
fetchPairings,
|
||||
@@ -40,12 +41,13 @@ export const getBrewsData = createServerFn({ method: 'GET' }).handler(async () =
|
||||
})
|
||||
|
||||
export const getMenuData = createServerFn({ method: 'GET' }).handler(async () => {
|
||||
const [categories, items, pairings] = await Promise.all([
|
||||
const [categories, items, pairings, ingredients] = await Promise.all([
|
||||
fetchMenuCategories(),
|
||||
fetchMenuItems(),
|
||||
fetchPairings(),
|
||||
fetchIngredients(),
|
||||
])
|
||||
return { categories, items, pairings }
|
||||
return { categories, items, pairings, ingredients }
|
||||
})
|
||||
|
||||
export const getVisitData = createServerFn({ method: 'GET' }).handler(() => fetchSettings())
|
||||
|
||||
+6
-1
@@ -9,10 +9,11 @@
|
||||
import seed from '~/data/content.json'
|
||||
// The food menu lives in its own module (shared with scripts/update-menu.mjs)
|
||||
// instead of content.json, since it is synced by its own script.
|
||||
import { MENU_CATEGORIES, MENU_ITEMS } from '~/data/menu-data.mjs'
|
||||
import { INGREDIENTS, MENU_CATEGORIES, MENU_ITEMS } from '~/data/menu-data.mjs'
|
||||
import type {
|
||||
Brew,
|
||||
Experience,
|
||||
Ingredient,
|
||||
MenuCategory,
|
||||
MenuItem,
|
||||
Pairing,
|
||||
@@ -79,6 +80,10 @@ export async function fetchMenuItems(): Promise<MenuItem[]> {
|
||||
return orFallback(await pbList<MenuItem>('menu_items'), MENU_ITEMS as unknown as MenuItem[])
|
||||
}
|
||||
|
||||
export async function fetchIngredients(): Promise<Ingredient[]> {
|
||||
return orFallback(await pbList<Ingredient>('ingredients'), INGREDIENTS as unknown as Ingredient[])
|
||||
}
|
||||
|
||||
export async function fetchPairings(): Promise<Pairing[]> {
|
||||
return orFallback(await pbList<Pairing>('pairings'), seed.pairings)
|
||||
}
|
||||
|
||||
+14
-2
@@ -65,6 +65,18 @@ export interface MenuCategory {
|
||||
sort: number
|
||||
}
|
||||
|
||||
export interface Ingredient {
|
||||
/** PocketBase record id (absent on code fallback data). */
|
||||
id?: string
|
||||
uid: string
|
||||
name: string
|
||||
/** Emoji shown as the ingredient's icon on menu cards. */
|
||||
icon: string
|
||||
/** 'veg' | 'nonveg' — an item is non-veg when any ingredient is. */
|
||||
diet_class: 'veg' | 'nonveg'
|
||||
sort: number
|
||||
}
|
||||
|
||||
export interface MenuItem {
|
||||
uid: string
|
||||
category: string
|
||||
@@ -75,8 +87,8 @@ export interface MenuItem {
|
||||
description?: string
|
||||
/** Rupees as a decimal number; paise after the point (449.5 = ₹449.50). */
|
||||
price: number
|
||||
/** Dietary status; 'mixed' items (e.g. Caesar Salad) get no badge. */
|
||||
diet?: 'veg' | 'nonveg' | 'mixed'
|
||||
/** Ingredient record ids (from PocketBase) or uids (from the fallback). */
|
||||
ingredients?: string[]
|
||||
pairing?: string
|
||||
tag?: string
|
||||
image?: string
|
||||
|
||||
+12
-2
@@ -1,6 +1,15 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { getMenuData } from '~/lib/data'
|
||||
import { MenuBrowser } from '~/components/menu-browser'
|
||||
import type { Ingredient } from '~/lib/types'
|
||||
|
||||
/**
|
||||
* Menu item ingredient fields hold PocketBase record ids, while the offline
|
||||
* fallback carries uids — index both so either path resolves.
|
||||
*/
|
||||
function indexIngredients(ingredients: Ingredient[]): Map<string, Ingredient> {
|
||||
return new Map(ingredients.flatMap((ing) => [[ing.id ?? ing.uid, ing], [ing.uid, ing]] as const))
|
||||
}
|
||||
|
||||
export const Route = createFileRoute('/menu')({
|
||||
head: () => ({
|
||||
@@ -18,7 +27,8 @@ export const Route = createFileRoute('/menu')({
|
||||
})
|
||||
|
||||
function MenuPage() {
|
||||
const { categories, items, pairings } = Route.useLoaderData()
|
||||
const { categories, items, pairings, ingredients } = Route.useLoaderData()
|
||||
const ingredientIndex = indexIngredients(ingredients as Ingredient[])
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col">
|
||||
@@ -44,7 +54,7 @@ function MenuPage() {
|
||||
</section>
|
||||
|
||||
{/* Interactive Menu + Sticky Filter */}
|
||||
<MenuBrowser categories={categories} items={items} />
|
||||
<MenuBrowser categories={categories} items={items} ingredientIndex={ingredientIndex} />
|
||||
|
||||
{/* Pairing Recommendations Banner */}
|
||||
<section className="mt-space-2xl w-full bg-surface-container-low py-space-xl">
|
||||
|
||||
Reference in New Issue
Block a user