top of page

Ordering Menu Carousel Design & Implementation Plan

  • Writer: Onifade R. E. Colbert III
    Onifade R. E. Colbert III
  • May 5
  • 5 min read

🍪 Ordering Menu Carousel — Design & Implementation Plan

This document outlines the full analysis, design decisions, and Velo (Wix Code) implementation for transforming the Onifade's Bakery ordering menu into an interactive, visually engaging carousel format.

📋 Step 1: Current Menu Layout Analysis

The site currently uses the Wix Restaurants Menus app with the following structure:

  • 5 Active Menus: YUMMIES!!!, Wet Your Whistle (Drinks), Holiday Menu, Delivery & Pickup, Meet the Community Behind the Counter

  • YUMMIES!!! Menu — 6 Sections: COOKKIESSSS!!!! (15 items), Boogie Bites (4 items), Let Them Eat Cake!! (9 items), Bars on Bars on Bars (9 items), Who Wants Pie? (8 items), The Wonderful World of Cupcakes!! (2 items)

  • Current Layout: Standard vertical list/grid — items displayed in a static scrollable list per section

  • Pain Points: Long scroll required to browse all items; no visual hierarchy between featured and regular items; mobile experience requires excessive scrolling

🎨 Step 2: Carousel Interface Design

The carousel design transforms each menu section into a horizontally scrollable card carousel. Here are the design specifications:

Card Design (per item)

  • Card Size: 280px wide × 360px tall (desktop); 240px × 320px (mobile)

  • Image Area: Top 60% of card — full-width product photo with rounded top corners (12px radius)

  • Content Area: Bottom 40% — item name (bold, 18px), short description (2-line truncated, 14px gray), price badge (pink/rose accent, bottom-right)

  • CTA Button: 'Add to Order' button — full width, brand pink (#c837a6), white text, rounded corners

  • Hover Effect: Subtle lift shadow (box-shadow elevation) + slight scale(1.02) transform

Navigation Controls

  • Left/Right Arrow Buttons: Circular buttons (48px), semi-transparent white background, positioned at vertical center of carousel

  • Dot Indicators: Row of dots below carousel showing current position; active dot uses brand pink color

  • Touch/Swipe Support: Native swipe gestures on mobile devices

  • Auto-scroll: Optional 5-second auto-advance (pauses on hover/touch)

  • Section Tabs: Horizontal tab bar at top to jump between menu sections (COOKIES, BOOGIE BITES, CAKES, BARS, PIES, CUPCAKES)

Responsiveness

  • Desktop (1024px+): Shows 3 cards at a time

  • Tablet (768px–1023px): Shows 2 cards at a time

  • Mobile (< 768px): Shows 1.2 cards (peek of next card to indicate scrollability)

⚙️ Step 3: Velo (Wix Code) Implementation

To implement the carousel on your Wix site, follow these steps in the Wix Editor with Velo enabled:

A. Page Setup in Wix Editor

  1. Open Wix Editor → Go to your Ordering/Menu page

  2. Enable Velo: Click 'Dev Mode' in the top bar → Turn on Dev Mode

  3. Add a Repeater element (ID: #menuCarousel) — this will serve as the carousel container

  4. Inside the Repeater item template, add: Image (#itemImage), Text (#itemName), Text (#itemDescription), Text (#itemPrice), Button (#addToOrderBtn)

  5. Add a HorizontalMenu or Tabs element (ID: #sectionTabs) above the carousel for section navigation

  6. Add Previous/Next buttons (IDs: #prevBtn, #nextBtn) flanking the carousel

B. Velo Page Code (paste into Page Code editor)

// ============================================================

// Onifade's Bakery — Menu Carousel Implementation (Velo)

// ============================================================

import wixWindow from 'wix-window';

// --- Menu Data (fetched from Wix Restaurants API) ---

const MENU_SECTIONS = [

{ id: 'a1e247ea-0c57-498e-a9be-4044ed48bda8', label: '🍪 Cookies' },

{ id: 'be9330c1-c3c0-4f76-96cc-b69eac8d88da', label: '🎉 Boogie Bites' },

{ id: 'dab968ad-5aa1-487d-9de5-69bd80cdbc41', label: '🎂 Cakes' },

{ id: '5eee8a25-fb16-4489-811d-a4c15d6a5a91', label: '🍫 Bars' },

{ id: '9ea7135d-c232-437f-a9c3-33dd87265542', label: '🥧 Pies' },

{ id: '70f12b79-cd30-4750-91ab-1021a16cbbfa', label: '🧁 Cupcakes' }

];

let currentSectionIndex = 0;

let currentItemIndex = 0;

let allSectionItems = {}; // Cache: sectionId -> items[]

let autoScrollTimer = null;


$w.onReady(async function () {

// Build section tab labels

buildSectionTabs();

// Load first section

await loadSection(0);

// Wire navigation buttons

$w('#prevBtn').onClick(() => navigateCarousel(-1));

$w('#nextBtn').onClick(() => navigateCarousel(1));

// Start auto-scroll

startAutoScroll();

});


function buildSectionTabs() {

// Populate tab labels from MENU_SECTIONS

const tabItems = MENU_SECTIONS.map((s, i) => ({ label: s.label, value: String(i) }));

$w('#sectionTabs').options = tabItems;

$w('#sectionTabs').value = '0';

$w('#sectionTabs').onChange(async (event) => {

const idx = parseInt(event.target.value);

await loadSection(idx);

});

}


async function loadSection(sectionIndex) {

currentSectionIndex = sectionIndex;

currentItemIndex = 0;

const section = MENU_SECTIONS[sectionIndex];

// Use cached items if available

if (!allSectionItems[section.id]) {

$w('#loadingSpinner').show();

// Fetch items via Wix HTTP Functions (backend)

const result = await fetch(`/_functions/getMenuItems?sectionId=${section.id}`);

const data = await result.json();

allSectionItems[section.id] = data.items.filter(item => item.visible);

$w('#loadingSpinner').hide();

}

renderCarousel(allSectionItems[section.id]);

}


function renderCarousel(items) {

// Map items to Repeater data format

const repeaterData = items.map(item => ({

_id: item.id,

name: item.name,

description: item.description ? item.description.substring(0, 80) + '...' : '',

price: item.priceInfo ? item.priceInfo.formattedPrice : (item.priceVariants ? 'From ' + item.priceVariants.variants[0].priceInfo.formattedPrice : 'See options'),

imageUrl: item.image ? item.image.url : 'https://static.wixstatic.com/media/b0e7dd_9dee316920b04b73876bd37c86ff6da0~mv2.jpg'

}));

$w('#menuCarousel').data = repeaterData;

$w('#menuCarousel').onItemReady(($item, itemData) => {

$item('#itemImage').src = itemData.imageUrl;

$item('#itemName').text = itemData.name;

$item('#itemDescription').text = itemData.description;

$item('#itemPrice').text = itemData.price;

$item('#addToOrderBtn').onClick(() => {

// Navigate to the Wix Restaurants ordering page with item pre-selected

wixWindow.openLightbox('ItemDetailLightbox', { itemId: itemData._id });

});

});

updateDotIndicators(items.length);

}


function navigateCarousel(direction) {

const section = MENU_SECTIONS[currentSectionIndex];

const items = allSectionItems[section.id] || [];

const visibleCount = getVisibleCardCount();

const maxIndex = Math.max(0, items.length - visibleCount);

currentItemIndex = Math.min(Math.max(currentItemIndex + direction, 0), maxIndex);

// Scroll the repeater to show currentItemIndex

$w('#menuCarousel').scrollTo(currentItemIndex);

updateNavButtons(items.length, visibleCount);

resetAutoScroll();

}


function getVisibleCardCount() {

const width = wixWindow.formFactor === 'Mobile' ? 1 : (wixWindow.formFactor === 'Tablet' ? 2 : 3);

return width;

}


function updateNavButtons(totalItems, visibleCount) {

currentItemIndex === 0 ? $w('#prevBtn').disable() : $w('#prevBtn').enable();

currentItemIndex >= totalItems - visibleCount ? $w('#nextBtn').disable() : $w('#nextBtn').enable();

}


function updateDotIndicators(totalItems) {

// Update dot repeater to show correct number of dots

const dots = Array.from({length: totalItems}, (_, i) => ({ _id: String(i), active: i === currentItemIndex }));

$w('#dotIndicators').data = dots;

$w('#dotIndicators').onItemReady(($item, dotData) => {

$item('#dot').style.backgroundColor = dotData.active ? '#c837a6' : '#ddd';

});

}


function startAutoScroll() {

autoScrollTimer = setInterval(() => navigateCarousel(1), 5000);

}


function resetAutoScroll() {

clearInterval(autoScrollTimer);

startAutoScroll();

}

C. Backend HTTP Function (http-functions.js)

Create a file at backend/http-functions.js with the following code to securely proxy the Wix Restaurants API:

import { ok, badRequest } from 'wix-http-functions';

import { fetch } from 'wix-fetch';

export async function get_getMenuItems(request) {

const sectionId = request.query.sectionId;

if (!sectionId) return badRequest({ body: JSON.stringify({ error: 'Missing sectionId' }) });

// Query sections to get itemIds

const sectionRes = await fetch(`https://www.wixapis.com/restaurants/menus-section/v1/sections/query`, {

method: 'POST',

headers: { 'Content-Type': 'application/json' },

body: JSON.stringify({ query: { filter: { id: { '$eq': sectionId } } } })

});

const sectionData = await sectionRes.json();

const itemIds = sectionData.sections[0]?.itemIds || [];

// Fetch items by IDs

const params = itemIds.map(id => `itemIds=${id}`).join('&');

const itemsRes = await fetch(`https://www.wixapis.com/restaurants/menus-item/v1/items?${params}&onlyVisible=true`, {

headers: { 'Content-Type': 'application/json' }

});

const itemsData = await itemsRes.json();

return ok({ body: JSON.stringify({ items: itemsData.items || [] }) });

}

📱 Step 4: Responsiveness Testing Checklist

  • Desktop Chrome/Firefox/Safari: 3-card view, arrow navigation, dot indicators

  • iPad/Tablet: 2-card view, touch swipe works

  • iPhone/Android: 1.2-card peek view, swipe navigation, auto-scroll pauses on touch

  • Section tabs: All 6 sections load correctly with proper item counts

  • Images: All product images load from Wix CDN (wixstatic.com)

  • Prices: Correctly shows single price or 'From $X.XX' for variant-priced items

  • Add to Order button: Opens item detail lightbox or navigates to ordering flow

📊 Menu Summary (Current Data)

  • COOKKIESSSS!!!! — 15 items (13 visible): Chocolate Chip, Butter, Snickerdoodle, Pecan Sandies, Salted Caramel, Peanut Butter, PB Chocolate, Macadamia White Choc, Oatmeal, S'mores, Cinnamon Roll, Fudge Mint, Stuffed Red Velvet

  • Boogie Bites — 4 items

  • Let Them Eat Cake!! — 9 items

  • Bars on Bars on Bars — 9 items

  • Who Wants Pie? — 8 items

  • The Wonderful World of Cupcakes!! — 2 items

This content was generated by AI.

 
 
 

Comments


bottom of page