lokesh341 commited on
Commit
8bcc74b
·
verified ·
1 Parent(s): 0139513

Update templates/menu.html

Browse files
Files changed (1) hide show
  1. templates/menu.html +101 -16
templates/menu.html CHANGED
@@ -9,9 +9,9 @@
9
  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
10
  <!-- Preload Placeholder Image -->
11
  <link rel="preload" href="/static/placeholder.jpg" as="image">
12
- <!-- Preload First Few Menu Item Images (Example) -->
13
  {% for section, items in ordered_menu.items() %}
14
- {% for item in items[:2] %} <!-- Preload images for the first 2 items in each section -->
15
  <link rel="preload" href="{{ item.Image1__c }}" as="image">
16
  {% endfor %}
17
  {% endfor %}
@@ -35,22 +35,22 @@
35
  margin: auto;
36
  display: flex;
37
  flex-direction: column;
38
- opacity: 0; /* Initially hidden for lazy loading */
39
  transition: opacity 0.3s ease-in-out;
40
  }
41
  .menu-card.visible {
42
- opacity: 1; /* Visible when in viewport */
43
  }
44
  .menu-image {
45
  height: 200px;
46
  width: 100%;
47
  object-fit: fill;
48
  border-radius: 15px 15px 0 0;
49
- opacity: 0; /* Initially hidden for fade-in effect */
50
  transition: opacity 0.5s ease-in-out;
51
  }
52
  .menu-image.loaded {
53
- opacity: 1; /* Fade in when loaded */
54
  }
55
  .card-title {
56
  font-size: 1.2rem;
@@ -350,6 +350,42 @@
350
  height: 40px;
351
  width: 40px;
352
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  @media (max-width: 576px) {
354
  .modal-dialog {
355
  max-width: 98%;
@@ -362,6 +398,10 @@
362
  width: 40px;
363
  height: 35px;
364
  }
 
 
 
 
365
  }
366
  </style>
367
  </head>
@@ -423,9 +463,7 @@
423
  {% for item in items %}
424
  <div class="col-md-6 mb-4">
425
  <div class="card menu-card">
426
- <!-- Use <picture> for WebP with fallback -->
427
  <picture>
428
- <!-- Assume item.Image1__c_webp is the WebP version (server-side generated) -->
429
  <source srcset="{{ item.Image1__c_webp if item.Image1__c_webp else item.Image1__c }}" type="image/webp">
430
  <img src="{{ item.Image1__c }}"
431
  srcset="{{ item.Image1__c }} 350w, {{ item.Image1__c_small if item.Image1__c_small else item.Image1__c }} 175w"
@@ -445,7 +483,7 @@
445
  <div class="d-flex flex-column align-item-center justify-content-center">
446
  <div>
447
  <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#itemModal"
448
- onclick="showItemDetails('{{ item.Name }}', '{{ item.Price__c }}', '{{ item.Image2__c }}', '{{ item.Description__c }}', '{{ item.Section__c }}','{{ selected_category }}')">
449
  ADD
450
  </button>
451
  </div>
@@ -484,6 +522,29 @@
484
  <p id="modal-price" class="text-muted text-center"></p>
485
  <p id="modal-description" class="text-secondary"></p>
486
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  <div id="first-row">
488
  <h6 id="first-row-title" style="display: none;">Customization Options</h6>
489
  <div class="addon-section">
@@ -531,7 +592,6 @@
531
  const menuCards = document.querySelectorAll('.menu-card');
532
  const menuImages = document.querySelectorAll('.menu-image');
533
 
534
- // Observer for menu cards (to show the card when in viewport)
535
  const cardObserver = new IntersectionObserver((entries, observer) => {
536
  entries.forEach(entry => {
537
  if (entry.isIntersecting) {
@@ -545,13 +605,12 @@
545
  threshold: 0.1
546
  });
547
 
548
- // Observer for images (to add fade-in effect when loaded)
549
  const imageObserver = new IntersectionObserver((entries, observer) => {
550
  entries.forEach(entry => {
551
  if (entry.isIntersecting) {
552
  const img = entry.target;
553
  img.onload = () => img.classList.add('loaded');
554
- img.onerror = () => img.classList.add('loaded'); // Ensure fade-in even if image fails
555
  observer.unobserve(img);
556
  }
557
  });
@@ -574,14 +633,41 @@
574
  };
575
  }
576
 
577
- function showItemDetails(name, price, image, description, section, selectedCategory) {
578
  document.getElementById('modal-name').innerText = name;
579
- document.getElementById('modal-price').innerText = `$${price}`;
580
  document.getElementById('modal-img').src = image || '/static/placeholder.jpg';
581
  document.getElementById('modal-description').innerText = description || 'No description available.';
582
  document.getElementById('addons-list').innerHTML = 'Loading customization options...';
583
  document.getElementById('modal-instructions').value = '';
584
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
585
  const modalSectionEl = document.getElementById('modal-section');
586
  modalSectionEl.setAttribute('data-section', section);
587
  modalSectionEl.setAttribute('data-category', selectedCategory);
@@ -802,12 +888,11 @@
802
  });
803
  }
804
 
805
- // Add Debounce to Search
806
  document.getElementById('searchBar').addEventListener('keyup', debounce(filterMenu, 300));
807
 
808
  function addToCartFromModal() {
809
  const itemName = document.getElementById('modal-name').innerText;
810
- let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
811
 
812
  if (isNaN(itemPrice)) {
813
  alert('Invalid price for the item. Please check the item details.');
 
9
  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
10
  <!-- Preload Placeholder Image -->
11
  <link rel="preload" href="/static/placeholder.jpg" as="image">
12
+ <!-- Preload First Few Menu Item Images -->
13
  {% for section, items in ordered_menu.items() %}
14
+ {% for item in items[:2] %}
15
  <link rel="preload" href="{{ item.Image1__c }}" as="image">
16
  {% endfor %}
17
  {% endfor %}
 
35
  margin: auto;
36
  display: flex;
37
  flex-direction: column;
38
+ opacity: 0;
39
  transition: opacity 0.3s ease-in-out;
40
  }
41
  .menu-card.visible {
42
+ opacity: 1;
43
  }
44
  .menu-image {
45
  height: 200px;
46
  width: 100%;
47
  object-fit: fill;
48
  border-radius: 15px 15px 0 0;
49
+ opacity: 0;
50
  transition: opacity 0.5s ease-in-out;
51
  }
52
  .menu-image.loaded {
53
+ opacity: 1;
54
  }
55
  .card-title {
56
  font-size: 1.2rem;
 
350
  height: 40px;
351
  width: 40px;
352
  }
353
+ /* New Styles for Ingredients, Nutritional Info, and Allergens */
354
+ .modal-ingredients, .modal-nutritional-info, .modal-allergens {
355
+ margin-top: 15px;
356
+ }
357
+ .modal-ingredients h6, .modal-nutritional-info h6, .modal-allergens h6 {
358
+ font-size: 1.1rem;
359
+ font-weight: bold;
360
+ color: #343a40;
361
+ margin-bottom: 10px;
362
+ }
363
+ .modal-ingredients ul {
364
+ list-style: none;
365
+ padding: 0;
366
+ display: flex;
367
+ flex-wrap: wrap;
368
+ gap: 5px;
369
+ }
370
+ .modal-ingredients li {
371
+ font-size: 0.9rem;
372
+ color: #6c757d;
373
+ }
374
+ .modal-nutritional-info .nutritional-grid {
375
+ display: flex;
376
+ justify-content: space-between;
377
+ background-color: #f8f9fa;
378
+ padding: 10px;
379
+ border-radius: 5px;
380
+ }
381
+ .modal-nutritional-info .nutritional-item {
382
+ font-size: 0.9rem;
383
+ color: #343a40;
384
+ }
385
+ .modal-allergens p {
386
+ font-size: 0.9rem;
387
+ color: #dc3545; /* Red for allergens to highlight them */
388
+ }
389
  @media (max-width: 576px) {
390
  .modal-dialog {
391
  max-width: 98%;
 
398
  width: 40px;
399
  height: 35px;
400
  }
401
+ .modal-nutritional-info .nutritional-grid {
402
+ flex-direction: column;
403
+ gap: 5px;
404
+ }
405
  }
406
  </style>
407
  </head>
 
463
  {% for item in items %}
464
  <div class="col-md-6 mb-4">
465
  <div class="card menu-card">
 
466
  <picture>
 
467
  <source srcset="{{ item.Image1__c_webp if item.Image1__c_webp else item.Image1__c }}" type="image/webp">
468
  <img src="{{ item.Image1__c }}"
469
  srcset="{{ item.Image1__c }} 350w, {{ item.Image1__c_small if item.Image1__c_small else item.Image1__c }} 175w"
 
483
  <div class="d-flex flex-column align-item-center justify-content-center">
484
  <div>
485
  <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#itemModal"
486
+ onclick="showItemDetails('{{ item.Name }}', '{{ item.Price__c }}', '{{ item.Image2__c }}', '{{ item.Description__c }}', '{{ item.Section__c }}', '{{ selected_category }}', {{ item.Ingredients__c | tojson }}, {{ item.NutritionalInfo__c | tojson }}, {{ item.Allergens__c | tojson }})">
487
  ADD
488
  </button>
489
  </div>
 
522
  <p id="modal-price" class="text-muted text-center"></p>
523
  <p id="modal-description" class="text-secondary"></p>
524
 
525
+ <!-- Ingredients Section -->
526
+ <div class="modal-ingredients">
527
+ <h6>Ingredients</h6>
528
+ <ul id="modal-ingredients-list"></ul>
529
+ </div>
530
+
531
+ <!-- Nutritional Info Section -->
532
+ <div class="modal-nutritional-info">
533
+ <h6>Nutritional Info</h6>
534
+ <div class="nutritional-grid" id="modal-nutritional-info-grid">
535
+ <div class="nutritional-item" id="modal-calories"></div>
536
+ <div class="nutritional-item" id="modal-protein"></div>
537
+ <div class="nutritional-item" id="modal-carbs"></div>
538
+ <div class="nutritional-item" id="modal-fats"></div>
539
+ </div>
540
+ </div>
541
+
542
+ <!-- Allergens Section -->
543
+ <div class="modal-allergens">
544
+ <h6>Allergens</h6>
545
+ <p id="modal-allergens-list"></p>
546
+ </div>
547
+
548
  <div id="first-row">
549
  <h6 id="first-row-title" style="display: none;">Customization Options</h6>
550
  <div class="addon-section">
 
592
  const menuCards = document.querySelectorAll('.menu-card');
593
  const menuImages = document.querySelectorAll('.menu-image');
594
 
 
595
  const cardObserver = new IntersectionObserver((entries, observer) => {
596
  entries.forEach(entry => {
597
  if (entry.isIntersecting) {
 
605
  threshold: 0.1
606
  });
607
 
 
608
  const imageObserver = new IntersectionObserver((entries, observer) => {
609
  entries.forEach(entry => {
610
  if (entry.isIntersecting) {
611
  const img = entry.target;
612
  img.onload = () => img.classList.add('loaded');
613
+ img.onerror = () => img.classList.add('loaded');
614
  observer.unobserve(img);
615
  }
616
  });
 
633
  };
634
  }
635
 
636
+ function showItemDetails(name, price, image, description, section, selectedCategory, ingredients, nutritionalInfo, allergens) {
637
  document.getElementById('modal-name').innerText = name;
638
+ document.getElementById('modal-price').innerText = `Starting from $${price}`;
639
  document.getElementById('modal-img').src = image || '/static/placeholder.jpg';
640
  document.getElementById('modal-description').innerText = description || 'No description available.';
641
  document.getElementById('addons-list').innerHTML = 'Loading customization options...';
642
  document.getElementById('modal-instructions').value = '';
643
 
644
+ // Display Ingredients
645
+ const ingredientsList = document.getElementById('modal-ingredients-list');
646
+ ingredientsList.innerHTML = '';
647
+ if (ingredients && ingredients.length > 0) {
648
+ ingredients.forEach(ingredient => {
649
+ const li = document.createElement('li');
650
+ li.innerText = ingredient;
651
+ ingredientsList.appendChild(li);
652
+ });
653
+ } else {
654
+ ingredientsList.innerHTML = '<li>No ingredients listed.</li>';
655
+ }
656
+
657
+ // Display Nutritional Info
658
+ document.getElementById('modal-calories').innerText = `Calories: ${nutritionalInfo?.Calories || 'N/A'}`;
659
+ document.getElementById('modal-protein').innerText = `Protein: ${nutritionalInfo?.Protein || 'N/A'}`;
660
+ document.getElementById('modal-carbs').innerText = `Carbs: ${nutritionalInfo?.Carbs || 'N/A'}`;
661
+ document.getElementById('modal-fats').innerText = `Fats: ${nutritionalInfo?.Fats || 'N/A'}`;
662
+
663
+ // Display Allergens
664
+ const allergensList = document.getElementById('modal-allergens-list');
665
+ if (allergens && allergens.length > 0) {
666
+ allergensList.innerText = allergens.join(', ');
667
+ } else {
668
+ allergensList.innerText = 'None';
669
+ }
670
+
671
  const modalSectionEl = document.getElementById('modal-section');
672
  modalSectionEl.setAttribute('data-section', section);
673
  modalSectionEl.setAttribute('data-category', selectedCategory);
 
888
  });
889
  }
890
 
 
891
  document.getElementById('searchBar').addEventListener('keyup', debounce(filterMenu, 300));
892
 
893
  function addToCartFromModal() {
894
  const itemName = document.getElementById('modal-name').innerText;
895
+ let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('Starting from $', ''));
896
 
897
  if (isNaN(itemPrice)) {
898
  alert('Invalid price for the item. Please check the item details.');