Spaces:
Runtime error
Runtime error
Update templates/menu.html
Browse files- templates/menu.html +48 -10
templates/menu.html
CHANGED
@@ -9,6 +9,12 @@
|
|
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 |
<style>
|
13 |
body {
|
14 |
font-family: Arial, sans-serif;
|
@@ -40,6 +46,11 @@
|
|
40 |
width: 100%;
|
41 |
object-fit: fill;
|
42 |
border-radius: 15px 15px 0 0;
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
44 |
.card-title {
|
45 |
font-size: 1.2rem;
|
@@ -412,9 +423,19 @@
|
|
412 |
{% for item in items %}
|
413 |
<div class="col-md-6 mb-4">
|
414 |
<div class="card menu-card">
|
415 |
-
|
416 |
-
|
417 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
418 |
<div class="addbutton">
|
419 |
<div class="card-body d-flex align-items-center justify-content-between">
|
420 |
<div>
|
@@ -505,26 +526,43 @@
|
|
505 |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
|
506 |
|
507 |
<script>
|
508 |
-
// Lazy Load Menu Items with Intersection Observer
|
509 |
document.addEventListener('DOMContentLoaded', function () {
|
510 |
const menuCards = document.querySelectorAll('.menu-card');
|
|
|
511 |
|
512 |
-
|
|
|
513 |
entries.forEach(entry => {
|
514 |
if (entry.isIntersecting) {
|
515 |
entry.target.classList.add('visible');
|
516 |
-
observer.unobserve(entry.target);
|
517 |
}
|
518 |
});
|
519 |
}, {
|
520 |
root: null,
|
521 |
rootMargin: '0px',
|
522 |
-
threshold: 0.1
|
523 |
});
|
524 |
|
525 |
-
|
526 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
527 |
});
|
|
|
|
|
|
|
528 |
});
|
529 |
|
530 |
// Debounce Function for Search
|
@@ -745,7 +783,7 @@
|
|
745 |
|
746 |
if (itemName.includes(input) || (itemSection && itemSection.includes(input))) {
|
747 |
item.style.display = 'block';
|
748 |
-
item.classList.add('visible');
|
749 |
matchedSections.add(item.closest('.row'));
|
750 |
} else {
|
751 |
item.style.display = 'none';
|
|
|
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 %}
|
18 |
<style>
|
19 |
body {
|
20 |
font-family: Arial, sans-serif;
|
|
|
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;
|
|
|
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"
|
432 |
+
sizes="(max-width: 576px) 175px, 350px"
|
433 |
+
class="card-img-top menu-image"
|
434 |
+
alt="{{ item.Name }}"
|
435 |
+
width="350" height="200"
|
436 |
+
loading="lazy"
|
437 |
+
onerror="this.src='/static/placeholder.jpg';">
|
438 |
+
</picture>
|
439 |
<div class="addbutton">
|
440 |
<div class="card-body d-flex align-items-center justify-content-between">
|
441 |
<div>
|
|
|
526 |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
|
527 |
|
528 |
<script>
|
529 |
+
// Lazy Load Menu Items and Images with Intersection Observer
|
530 |
document.addEventListener('DOMContentLoaded', function () {
|
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) {
|
538 |
entry.target.classList.add('visible');
|
539 |
+
observer.unobserve(entry.target);
|
540 |
}
|
541 |
});
|
542 |
}, {
|
543 |
root: null,
|
544 |
rootMargin: '0px',
|
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 |
+
});
|
558 |
+
}, {
|
559 |
+
root: null,
|
560 |
+
rootMargin: '0px',
|
561 |
+
threshold: 0.1
|
562 |
});
|
563 |
+
|
564 |
+
menuCards.forEach(card => cardObserver.observe(card));
|
565 |
+
menuImages.forEach(img => imageObserver.observe(img));
|
566 |
});
|
567 |
|
568 |
// Debounce Function for Search
|
|
|
783 |
|
784 |
if (itemName.includes(input) || (itemSection && itemSection.includes(input))) {
|
785 |
item.style.display = 'block';
|
786 |
+
item.classList.add('visible');
|
787 |
matchedSections.add(item.closest('.row'));
|
788 |
} else {
|
789 |
item.style.display = 'none';
|