lokesh341's picture
Update templates/menu.html
e5cd1a2 verified
raw
history blame
76.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Menu</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
<!-- Preload Critical Resources -->
<link rel="preload" href="/static/placeholder.mp4" as="video">
{% for section, items in ordered_menu.items() %}
{% for item in items[:1] %}
<link rel="preload" href="{{ item.Video1__c | default('/static/placeholder.mp4') }}" as="video" fetchpriority="high">
{% endfor %}
{% endfor %}
<style>
body {
font-family: Arial, sans-serif;
background-color: #fdf4e3;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
padding-bottom: 70px;
}
.container {
max-width: 900px;
}
.menu-card {
max-width: 350px;
border-radius: 15px;
overflow: hidden;
background-color: #fff;
margin: auto;
display: flex;
flex-direction: column;
opacity: 0;
transition: opacity 0.3s ease-in-out;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.menu-card.visible {
opacity: 1;
}
.menu-card.highlighted {
border: 3px solid #0FAA39;
box-shadow: 0 0 10px rgba(15, 170, 57, 0.5);
}
.menu-video {
height: 200px;
width: 100%;
object-fit: cover;
border-radius: 15px 15px 0 0;
opacity: 0;
transition: opacity 0.5s ease-in-out;
background-color: #000;
}
.menu-video.loaded {
opacity: 1;
}
.menu-card:hover .menu-video {
opacity: 1;
transform: scale(1.05);
}
.menu-card .card-body .card-title {
font-size: 1.2rem;
font-weight: 600;
margin: 10px 0;
color: #333333;
}
.menu-card .card-body .card-text.price {
font-size: 1rem;
font-weight: 500;
color: #000000;
margin-bottom: 5px;
}
.addbutton .btn {
background-color: #28a745;
color: white;
padding: 10px 20px;
font-size: 16px;
font-weight: bold;
border-radius: 5px;
border: none;
transition: background-color 0.3s ease;
margin-left: 13px;
}
.addbutton .btn:hover {
background-color: #218838;
}
.button-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
}
.customisable-text {
color: #0FAA39;
font-size: 10px;
font-weight: 500;
margin: 0;
text-align: center;
line-height: 1;
}
.btn-primary {
font-size: 12px;
font-weight: bold;
border-radius: 8px;
width: 70px;
height: 35px;
background-color: #0FAA39;
border-color: #0FAA39;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
transition: background-color 0.3s ease, transform 0.1s ease;
}
.btn-primary:hover {
background-color: #0D9232;
border-color: #0D9232;
transform: scale(1.05);
}
.btn-primary:active,
.btn-primary:focus {
background-color: #0B7A29;
border-color: #0B7A29;
box-shadow: none;
transform: scale(0.98);
}
.avatar-dropdown-container {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
justify-content: center;
}
.avatar-icon {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #007bff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
font-weight: bold;
}
.dropdown-menu {
position: absolute;
right: 0;
top: 100%;
background-color: #fff8f0;
border-radius: 5px;
width: 220px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
display: none;
border: 1px solid #ffd8b1;
}
.dropdown-menu .dropdown-item {
padding: 12px 16px;
text-decoration: none;
color: #333;
border-bottom: 1px solid #ffd8b1;
display: block;
font-size: 15px;
transition: background-color 0.2s ease;
}
.dropdown-menu .dropdown-item:last-child {
border-bottom: none;
}
.dropdown-menu .dropdown-item:hover {
background-color: #ffe4c4;
color: #333;
}
.fixed-top-bar {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 54px;
background: linear-gradient(45deg, #FFA07A, #FFB347);
color: white;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 1000;
}
.search-bar-container {
position: absolute;
left: 20px;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
width: 300px;
max-width: 90%;
position: relative;
}
.search-bar-container input {
width: 100%;
padding: 8px 40px 8px 40px;
font-size: 16px;
border-radius: 25px;
border: none;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
outline: none;
}
.search-bar-container input::placeholder {
color: #888;
}
.search-bar-container input:focus {
border-bottom: 2px solid #FFA07A;
}
.search-icon {
position: absolute;
left: 15px;
font-size: 18px;
color: #888;
}
.mic-icon {
position: absolute;
right: 15px;
font-size: 18px;
color: #888;
cursor: pointer;
transition: color 0.3s ease;
}
.mic-icon.active {
color: #007bff;
}
/* Addon Section */
.addon-section {
background-color: #fff;
border-radius: 10px;
margin-bottom: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.2s ease;
}
.addon-section:hover {
transform: translateY(-2px);
}
.addon-section h6 {
margin: 0;
padding: 12px 15px;
font-size: 1.1rem;
font-weight: 600;
color: #fff;
background: linear-gradient(45deg, #FFA07A, #FFB347);
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.addon-section h6::after {
content: '\25BC';
font-size: 0.9rem;
transition: transform 0.2s ease;
}
.addon-section.collapsed h6::after {
transform: rotate(180deg);
}
.addon-section .form-check {
display: flex;
flex-direction: row-reverse;
align-items: center;
justify-content: space-between;
margin: 10px 15px;
padding: 0;
}
.addon-section .form-check-input {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border: 2px solid #6c757d;
border-radius: 4px;
background-color: #fff;
position: relative;
margin-left: 10px;
cursor: pointer;
transition: all 0.2s ease;
}
.addon-section .form-check-input:checked {
background-color: #0FAA39;
border-color: #0FAA39;
}
.addon-section .form-check-input:checked::before {
content: '\2713';
font-size: 12px;
position: absolute;
top: 2px;
left: 4px;
color: white;
animation: checkmark 0.2s ease-in-out;
}
.addon-section .form-check-input:hover {
transform: scale(1.1);
border-color: #0FAA39;
}
.addon-section .form-check-input:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(15, 170, 57, 0.2);
}
.addon-section .form-check-label {
font-size: 0.95rem;
color: #343a40;
cursor: pointer;
flex: 1;
padding: 5px 8px;
border-radius: 4px;
transition: background-color 0.2s ease;
text-align: left;
}
.addon-section .form-check-label:hover {
background-color: #e6f4ea;
}
.addon-section .form-check-label .extra-charge {
color: #FFA07A;
font-weight: 600;
margin-left: 8px;
}
.addon-options {
max-height: 500px;
opacity: 1;
overflow: hidden;
transition: max-height 0.3s ease, opacity 0.3s ease;
}
.addon-options.collapsed {
max-height: 0;
opacity: 0;
}
.addon-loading {
display: flex;
justify-content: center;
align-items: center;
padding: 15px;
}
.addon-loading::after {
content: '';
width: 20px;
height: 20px;
border: 3px solid #0FAA39;
border-top: 3px solid transparent;
border-radius: 50%;
animation: spin 1s linear infinite;
}
/* Soft Drinks Modal Styling */
#softDrinkModal .modal-dialog {
max-width: 400px;
margin: 1.75rem auto;
animation: fadeInModal 0.3s ease-out;
}
#softDrinkModal .modal-content {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
background-color: #fff;
overflow: hidden;
}
#softDrinkModal .modal-header {
background: linear-gradient(45deg, #FFA07A, #FFB347);
border-top-left-radius: 12px;
border-top-right-radius: 12px;
padding: 12px 15px;
border-bottom: none;
}
#softDrinkModal .modal-title {
font-size: 1.3rem;
font-weight: 600;
color: #fff;
}
#softDrinkModal .modal-body {
padding: 20px;
text-align: center;
}
#softDrinkModal .modal-body img {
max-height: 160px;
width: 100%;
object-fit: cover;
border-radius: 8px;
margin-bottom: 15px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
#softDrinkModal .modal-body h5 {
font-size: 1.4rem;
font-weight: 600;
color: #333333;
margin-bottom: 10px;
}
#softDrinkModal .modal-body p {
font-size: 1.2rem;
font-weight: 500;
color: #000000;
margin-bottom: 20px;
}
#softDrinkModal .modal-body p::before {
content: '$';
color: #FFA07A;
font-weight: 600;
margin-right: 2px;
}
#softDrinkModal .quantity-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
#softDrinkModal .quantity-controls .btn {
width: 32px;
height: 32px;
border-radius: 50%;
padding: 0;
font-size: 1.1rem;
line-height: 32px;
text-align: center;
background-color: #e9ecef;
border: none;
color: #333;
transition: background-color 0.2s ease, transform 0.1s ease;
}
#softDrinkModal .quantity-controls .btn:hover {
background-color: #d1d4d7;
transform: scale(1.1);
}
#softDrinkModal .quantity-controls .btn:active {
transform: scale(0.95);
}
#softDrinkModal .quantity-controls input {
width: 50px;
height: 32px;
text-align: center;
font-size: 1rem;
font-weight: 600;
border: 1px solid #ced4da;
border-radius: 6px;
background-color: #f8f9fa;
}
#softDrinkModal .modal-footer {
padding: 15px;
border-top: none;
display: flex;
justify-content: space-between;
align-items: center;
}
#softDrinkModal .modal-footer .btn-primary {
background-color: #0FAA39;
border-color: #0FAA39;
padding: 12px 30px;
font-size: 1.1rem;
font-weight: 600;
border-radius: 8px;
transition: background-color 0.2s ease, transform 0.1s ease;
width: auto;
}
#softDrinkModal .modal-footer .btn-primary:hover {
background-color: #0D9232;
transform: scale(1.05);
}
#softDrinkModal .modal-footer .btn-primary:active {
background-color: #0B7A29;
transform: scale(0.98);
}
#softDrinkModal .modal-footer .quantity-controls-footer {
display: flex;
gap: 12px;
}
#softDrinkModal .modal-footer .quantity-controls-footer .btn {
width: 32px;
height: 32px;
border-radius: 50%;
padding: 0;
font-size: 1.1rem;
line-height: 32px;
text-align: center;
background-color: #e9ecef;
border: none;
color: #333;
transition: background-color 0.2s ease, transform 0.1s ease;
}
#softDrinkModal .modal-footer .quantity-controls-footer .btn:hover {
background-color: #d1d4d7;
transform: scale(1.1);
}
#softDrinkModal .modal-footer .quantity-controls-footer .btn:active {
transform: scale(0.95);
}
/* Filter Form Styling */
#filter-form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
.form-label {
font-size: 1.2rem;
font-weight: 600;
color: #333;
margin-bottom: 10px;
}
.toggle-container {
display: flex;
align-items: center;
gap: 10px;
margin: 8px 0;
}
.custom-toggle {
appearance: none;
width: 48px;
height: 24px;
background-color: #ccc;
border-radius: 12px;
position: relative;
cursor: pointer;
transition: background-color 0.3s ease;
}
.custom-toggle:checked {
background: linear-gradient(45deg, #FFA07A, #FFB347);
}
.custom-toggle::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background-color: #fff;
border-radius: 50%;
transition: transform 0.3s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.custom-toggle:checked::before {
transform: translateX(24px);
}
.toggle-container label {
font-size: 1rem;
color: #333;
cursor: pointer;
}
@keyframes checkmark {
from { transform: scale(0); }
to { transform: scale(1); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeInModal {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
.modal-header {
padding: 10px 15px;
}
.modal-title {
font-size: 16px;
font-weight: bold;
}
.modal-body {
max-height: 60vh;
overflow-y: auto;
padding: 15px;
}
.modal-body #modal-img {
max-height: 200px;
width: 100%;
object-fit: cover;
border-radius: 8px;
margin-bottom: 10px;
}
.modal-body #modal-name {
font-size: 20px;
font-weight: bold;
text-align: center;
margin-bottom: 5px;
color: #333333;
}
.modal-body #modal-price {
font-size: 16px;
font-weight: 500;
color: #000000;
text-align: center;
margin-bottom: 10px;
}
.modal-body #modal-description {
font-size: 14px;
color: #6c757d;
margin-bottom: 15px;
}
.modal-body #modal-addons h5,
.modal-body #first-row h6 {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 15px;
color: #343a40;
}
.modal-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
}
.modal-footer .d-flex {
display: flex;
align-items: center;
gap: 10px;
}
.modal-footer .btn {
height: 40px;
padding: 0 15px;
}
.modal-footer .form-control {
width: 50px;
height: 40px;
text-align: center;
}
.modal-footer .btn-primary {
background-color: #0FAA39;
border-color: #0FAA39;
font-weight: bold;
padding: 10px 20px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
width: auto;
}
.modal-footer .btn-outline-secondary {
height: 40px;
width: 40px;
}
.item-details {
background-color: #f8f9fa;
border-radius: 8px;
padding: 10px;
margin: 10px 15px;
display: none;
}
.item-details.show {
display: block;
}
.item-details h6 {
font-size: 0.9rem;
font-weight: bold;
margin-bottom: 5px;
color: #333333;
}
.item-details p {
font-size: 0.85rem;
margin-bottom: 5px;
color: #333;
}
.item-details .nutritional-info {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
background-color: #e9ecef;
padding: 10px;
border-radius: 5px;
font-size: 0.85rem;
line-height: 1.5;
}
.toggle-details {
cursor: pointer;
color: #0FAA39;
font-size: 0.9rem;
margin-left: 15px;
margin-bottom: 10px;
display: inline-block;
}
.toggle-details:hover {
text-decoration: underline;
}
.quantity-selector {
display: flex;
align-items: center;
gap: 5px;
}
.quantity-selector .btn {
width: 25px;
height: 25px;
padding: 0;
font-size: 12px;
line-height: 25px;
text-align: center;
}
.quantity-selector .quantity-display {
width: 25px;
text-align: center;
font-size: 12px;
font-weight: bold;
line-height: 25px;
}
.quantity-selector .quantity-to-add,
.quantity-selector .quantity-to-remove {
width: 45px;
height: 25px;
font-size: 12px;
padding: 0 5px;
}
.modal-dialog {
max-height: 90vh;
}
.modal-body::-webkit-scrollbar {
width: 8px;
}
.modal-body::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.modal-body::-webkit-scrollbar-thumb {
background: #0FAA39;
border-radius: 10px;
}
.modal-body::-webkit-scrollbar-thumb:hover {
background: #0D9232;
}
.btn-primary:disabled {
opacity: 0.65;
cursor: not-allowed;
}
.quantity-selector select {
width: 60px;
height: 35px;
padding: 5px;
border-radius: 5px;
border: 1px solid #ced4da;
}
#custom-dish-form {
position: relative;
padding-bottom: 80px;
}
#custom-dish-form .btn-primary {
position: absolute;
right: 15px;
bottom: 15px;
width: auto;
padding: 10px 20px;
}
.bottom-action-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: white;
padding: 10px 20px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
max-width: 900px;
margin: 0 auto;
}
.bottom-action-bar .btn {
flex: 1;
margin: 0 5px;
padding: 10px 15px;
border-radius: 8px;
font-weight: bold;
font-size: 16px;
color: white;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
min-width: 0;
white-space: nowrap;
}
.bottom-action-bar .btn-order-history {
background-color: #FFA07A;
border-color: #FFA07A;
}
.bottom-action-bar .btn-order-history:hover {
background-color: #FF8C61;
border-color: #FF8C61;
}
.bottom-action-bar .btn-view-cart {
background-color: #0FAA39;
border-color: #0FAA39;
}
.bottom-action-bar .btn-view-cart:hover {
background-color: #0D9232;
border-color: #0D9232;
}
.cart-icon-badge {
background-color: white;
color: #0FAA39;
border-radius: 50%;
width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 12px;
margin-left: 8px;
}
/* Mobile-Specific Styles */
@media (max-width: 576px) {
.fixed-top-bar {
height: 60px;
padding: 10px;
}
.search-bar-container {
width: 80%;
max-width: 100%;
left: 10px;
top: 50%;
transform: translateY(-50%);
}
.search-bar-container input {
padding: 6px 35px 6px 35px;
font-size: 14px;
border-radius: 20px;
}
.search-icon {
left: 12px;
font-size: 16px;
}
.mic-icon {
right: 12px;
font-size: 16px;
}
.avatar-dropdown-container {
right: 10px;
}
.avatar-icon {
width: 40px;
height: 40px;
font-size: 20px;
}
.dropdown-menu {
width: 220px;
}
.dropdown-menu .dropdown-item {
padding: 12px 16px;
font-size: 15px;
}
.modal-dialog {
max-width: 90%;
margin: 10px auto;
}
.modal-header {
padding: 8px 12px;
}
.modal-title {
font-size: 14px;
}
.modal-body {
max-height: 50vh;
padding: 12px;
}
.modal-body #modal-img {
max-height: 150px;
width: 100%;
max-width: 150px;
margin: 0 auto 8px;
display: block;
}
.modal-body #modal-name {
font-size: 18px;
margin-bottom: 5px;
}
.modal-body #modal-price {
font-size: 14px;
margin-bottom: 8px;
}
.modal-body #modal-description {
font-size: 12px;
margin-bottom: 10px;
}
.modal-body .nutritional-info {
font-size: 10px;
margin-bottom: 5px;
}
.modal-body #modal-addons h5,
.modal-body #first-row h6 {
font-size: 1rem;
margin-bottom: 10px;
}
.modal-footer {
padding: 8px;
}
.modal-footer .btn {
height: 30px;
padding: 0 10px;
}
.modal-footer .form-control {
width: 30px;
height: 30px;
font-size: 12px;
font-weight: bold;
}
.modal-footer .btn-outline-secondary {
width: 25px;
height: 25px;
font-size: 12px;
line-height: 25px;
}
.modal-footer .btn-primary {
font-size: 12px;
height: 30px;
padding: 0 15px;
border-radius: 5px;
}
.btn-primary {
font-size: 10px;
width: 50px;
height: 25px;
}
.customisable-text {
font-size: 8px;
}
.button-container {
gap: 3px;
}
.quantity-selector .btn {
width: 18px;
height: 18px;
font-size: 9px;
line-height: 18px;
}
.quantity-selector .quantity-display {
width: 18px;
font-size: 9px;
line-height: 18px;
}
.quantity-selector .quantity-to-add,
.quantity-selector .quantity-to-remove {
width: 35px;
height: 18px;
font-size: 9px;
}
.quantity-selector select {
width: 50px;
height: 30px;
font-size: 12px;
}
.bottom-action-bar {
padding: 8px 10px;
}
.bottom-action-bar .btn {
padding: 8px 10px;
font-size: 14px;
}
.cart-icon-badge {
width: 18px;
height: 18px;
font-size: 10px;
margin-left: 5px;
}
/* Mobile-Specific Addon Styles */
.addon-section {
margin-bottom: 10px;
}
.addon-section h6 {
font-size: 1rem;
padding: 10px 12px;
}
.addon-section .form-check {
margin: 8px 12px;
}
.addon-section .form-check-input {
width: 18px;
height: 18px;
margin-left: 8px;
}
.addon-section .form-check-input:checked::before {
font-size: 10px;
top: 2px;
left: 3px;
}
.addon-section .form-check-label {
font-size: 0.85rem;
padding: 4px 6px;
}
.addon-section .form-check-label .extra-charge {
margin-left: 6px;
font-size: 0.8rem;
}
/* Mobile-Specific Soft Drinks Modal Styles */
#softDrinkModal .modal-dialog {
max-width: 90%;
}
#softDrinkModal .modal-content {
border-radius: 10px;
}
#softDrinkModal .modal-header {
padding: 10px 12px;
}
#softDrinkModal .modal-title {
font-size: 1.2rem;
}
#softDrinkModal .modal-body {
padding: 15px;
}
#softDrinkModal .modal-body img {
max-height: 130px;
margin-bottom: 12px;
}
#softDrinkModal .modal-body h5 {
font-size: 1.2rem;
margin-bottom: 8px;
}
#softDrinkModal .modal-body p {
font-size: 1rem;
margin-bottom: 15px;
}
#softDrinkModal .quantity-controls .btn {
width: 28px;
height: 28px;
font-size: 1rem;
line-height: 28px;
}
#softDrinkModal .quantity-controls input {
width: 45px;
height: 28px;
font-size: 0.9rem;
}
#softDrinkModal .modal-footer {
padding: 10px;
}
#softDrinkModal .modal-footer .btn-primary {
padding: 10px 25px;
font-size: 1rem;
}
#softDrinkModal .modal-footer .quantity-controls-footer .btn {
width: 28px;
height: 28px;
font-size: 1rem;
line-height: 28px;
}
/* Mobile-Specific Filter Form Styles */
#filter-form {
margin-bottom: 15px;
}
.form-label {
font-size: 1rem;
}
.toggle-container {
margin: 6px 0;
}
.custom-toggle {
width: 40px;
height: 20px;
}
.custom-toggle::before {
width: 16px;
height: 16px;
top: 2px;
left: 2px;
}
.custom-toggle:checked::before {
transform: translateX(20px);
}
.toggle-container label {
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="fixed-top-bar">
<div class="avatar-dropdown-container">
<div class="avatar-icon">
<span>{{ first_letter }}</span>
</div>
<div class="dropdown-menu">
<a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item">View Profile</a>
<a href="{{ url_for('orderhistory.order_history') }}" class="dropdown-item">Order History</a>
<a href="{{ url_for('order.order_summary') }}" class="dropdown-item">My Summary</a>
<a href="{{ url_for('logout') }}" class="dropdown-item">Logout</a>
</div>
</div>
<div class="search-bar-container">
<input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off">
<i class="bi bi-search search-icon"></i>
<i class="bi bi-mic mic-icon" id="micIcon"></i>
</div>
</div>
<form method="get" action="/menu" class="text-center mb-4" id="filter-form">
<label class="form-label fw-bold">Filters:</label>
<div class="toggle-container">
<!-- Veg Only Toggle -->
<input type="checkbox" id="veg-toggle" name="veg"
{% if selected_category == "Veg" %}checked{% endif %}
class="custom-toggle" onchange="handleToggle('veg')"
aria-label="Toggle Vegetarian filter">
<label for="veg-toggle">Veg</label>
</div>
<div class="toggle-container">
<!-- Customized Dish Toggle -->
<input type="radio" id="category-CustomizedDish" name="category" value="Customized Dish"
{% if selected_category == "Customized Dish" %}checked{% endif %}
class="custom-toggle" onchange="handleToggle('custom')"
aria-label="Toggle Customized Dish filter">
<label for="category-CustomizedDish">Customized Dish</label>
</div>
</form>
<div class="container mt-4">
{% if selected_category == "Customized Dish" %}
<div id="custom-dish-form" class="mt-4">
<h3>Create Your Custom Dish</h3>
<form method="POST" action="/customdish/generate_custom_dish">
<div class="mb-3">
<label for="custom-dish-name" class="form-label">Dish Name</label>
<input type="text" class="form-control" id="custom-dish-name" name="name" required>
</div>
<div class="mb-3 position-relative">
<label for="custom-dish-description" class="form-label">Dish Description</label>
<textarea class="form-control" id="custom-dish-description" name="description" required></textarea>
<div id="descriptionSuggestions" class="autocomplete-suggestions"></div>
</div>
<button type="submit" class="btn btn-primary">Submit Custom Dish</button>
</form>
</div>
{% else %}
{% if ordered_menu.items()|length == 0 %}
<p>No menu items available for this category.</p>
{% else %}
{% for section, items in ordered_menu.items() %}
<h3>{{ section }}</h3>
<div class="row">
{% for item in items %}
<div class="col-md-6 mb-4">
<div class="card menu-card" data-item-name="{{ item.Name | default('Unnamed Item') }}" data-item-section="{{ item.Section__c | default(section) }}">
<video
class="card-img-top menu-video"
muted
loop
preload="auto"
data-src="{{ item.Video1__c | default('/static/placeholder.mp4') }}"
poster="{{ item.Image1__c | default('/static/placeholder.jpg') }}"
width="350"
height="200"
onmouseover="this.play()"
onmouseout="this.pause(); this.currentTime = 0;"
onerror="this.poster='/static/placeholder.jpg';">
<source src="{{ item.Video1__c | default('/static/placeholder.mp4') }}" type="video/mp4">
Your browser does not support the video tag.
</video>
<div class="addbutton">
<div class="card-body d-flex align-items-center justify-content-between">
<div>
<h5 class="card-title">{{ item.Name | default('Unnamed Item') }}</h5>
<p class="card-text price">${{ item.Price__c | default('0.00') }}</p>
</div>
<div class="d-flex flex-column align-items-center justify-content-center">
<div class="button-container"
data-item-name="{{ item.Name | default('Unnamed Item') }}"
data-item-price="{{ item.Price__c | default('0.00') }}"
data-item-image="{{ item.Image1__c | default('/static/placeholder.jpg') }}"
data-item-section="{{ item.Section__c | default(section) }}"
data-item-category="{{ selected_category }}"
data-item-description="{{ item.Description__c | default('No description') }}"
data-item-image2="{{ item.Image2__c | default(item.Image1__c) }}">
{% if item.Section__c == 'Soft Drinks' %}
<button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)">ADD</button>
{% else %}
<button class="btn btn-primary"
data-bs-toggle="modal"
data-bs-target="#itemModal"
onclick="showItemDetails('{{ item.Name | default('Unnamed Item') }}', '{{ item.Price__c | default('0.00') }}', '{{ item.Image2__c | default(item.Image1__c) }}', '{{ item.Description__c | default('No description') }}', '{{ item.Section__c | default(section) }}', '{{ selected_category }}')">
ADD
</button>
{% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' %}
<span class="customisable-text">Customisable</span>
{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
{% if item.Section__c != 'Soft Drinks' %}
<div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
<div class="item-details" id="details-{{ item.Name | default('unnamed-item') | replace(' ', '-') }}">
<h6>Description</h6>
<p>{{ item.Description__c | default('No description available') }}</p>
<h6>Ingredients</h6>
<p>{{ item.Ingredientsinfo__c | default('Not specified') }}</p>
<h6>Nutritional Info</h6>
<p class="nutritional-info">{{ item.NutritionalInfo__c | default('Not available') }}</p>
<h6>Allergens</h6>
<p>{{ item.Allergens__c | default('None listed') }}</p>
</div>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endfor %}
{% endif %}
{% endif %}
</div>
<div class="bottom-action-bar">
<a href="{{ url_for('orderhistory.order_history') }}" class="btn btn-order-history">
<i class="bi bi-clock-history"></i> Order History
</a>
<a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart">
<i class="bi bi-cart"></i> View Cart
<span id="cart-item-count" class="cart-icon-badge" style="display: none;">0</span>
</a>
</div>
<!-- Modal for Item Details -->
<div class="modal fade" id="itemModal" tabindex="-1" aria-labelledby="itemModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="itemModalLabel">Item Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<img id="modal-img" class="img-fluid rounded mb-3 d-block mx-auto" alt="Item Image" style="max-height: 200px; object-fit: cover;">
<h5 id="modal-name" class="fw-bold text-center"></h5>
<p id="modal-price" class="text-muted text-center"></p>
<p id="modal-description" class="text-secondary"></p>
<div id="modal-addons" class="modal-addons mt-4">
<h5>Customization Options</h5>
<div id="addons-list" class="addons-container addon-loading"></div>
</div>
<div class="mt-4">
<h6>Special Instructions</h6>
<textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
</div>
<span id="modal-section" data-section="" data-category="" style="display: none;"></span>
</div>
<div class="modal-footer d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
<input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;"/>
<button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
</div>
<button type="button" class="btn btn-primary" onclick="addToCartFromModal()">Add to Cart</button>
</div>
</div>
</div>
</div>
<!-- Modal for Soft Drinks Quantity Selection -->
<div class="modal fade" id="softDrinkModal" tabindex="-1" aria-labelledby="softDrinkModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="softDrinkModalLabel">Select Quantity</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<img id="soft-drink-image" class="img-fluid rounded mb-3 d-block mx-auto" alt="Soft Drink Image">
<div class="text-center mb-3">
<h5 id="soft-drink-name"></h5>
<p id="soft-drink-price"></p>
</div>
<div class="quantity-controls">
<button type="button" class="btn" id="soft-drink-decrease" onclick="updateSoftDrinkQuantity(-1)" aria-label="Decrease quantity by 1">-</button>
<input type="text" class="form-control text-center" id="soft-drink-quantity" value="1" readonly aria-label="Selected quantity">
<button type="button" class="btn" id="soft-drink-increase" onclick="updateSoftDrinkQuantity(1)" aria-label="Increase quantity by 1">+</button>
</div>
</div>
<div class="modal-footer">
<div class="quantity-controls-footer">
<button type="button" class="btn" id="soft-drink-decrease-footer" onclick="updateSoftDrinkQuantity(-1)" aria-label="Decrease quantity by 1">-1</button>
<button type="button" class="btn" id="soft-drink-increase-footer" onclick="updateSoftDrinkQuantity(1)" aria-label="Increase quantity by 1">+1</button>
</div>
<button type="button" class="btn btn-primary" onclick="addSoftDrinkToCart()" aria-label="Add soft drink to cart">Add to Cart</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<script>
let isProcessingRequest = false;
let currentSoftDrinkButton = null;
let baseItemPrice = 0;
const menuItems = [
{% for section, items in ordered_menu.items() %}
{% for item in items %}
{
name: "{{ item.Name | default('Unnamed Item') }}",
section: "{{ item.Section__c | default(section) }}"
},
{% endfor %}
{% endfor %}
];
const ingredientsList = [
"Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
"Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
"Chili Sauce", "Coconut Milk", "Coriander Powder", "Cornflour", "Cream", "Cumin Powder",
"Cumin Seeds", "Curd (Yogurt)", "Curry Leaves", "Fish (e.g., King Fish or Salmon)",
"Fresh Coriander Leaves", "Garam Masala", "Garlic", "Ghee (Clarified Butter)", "Ginger",
"Ginger-Garlic Paste", "Goat Meat (Mutton)", "Green Chilies", "Honey",
"Kasuri Methi (dried fenugreek leaves)", "Lemon Juice", "Mango Puree", "Mint Leaves",
"Mixed Vegetables (Carrot, Peas, Potato, Cauliflower)", "Mixed Vegetables (Carrot, Peas, Potato)",
"Mustard Seeds", "Mutton (Goat Meat)", "Oil", "Oil (for frying)", "Onion",
"Paneer (Indian Cottage Cheese)", "Peas", "Potatoes", "Prawns", "Red Chili Powder",
"Rice Flour", "Saffron", "Salt", "Soy Sauce", "Spring Onion", "Tamarind (for sourness)",
"Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
"Whole Wheat Flour", "Yogurt (Curd)"
];
function addToCartLocalStorage(payload) {
let cart = JSON.parse(localStorage.getItem('cart')) || [];
const existingItem = cart.find(item =>
item.itemName === payload.itemName &&
item.instructions === payload.instructions &&
JSON.stringify(item.addons) === JSON.stringify(payload.addons)
);
if (existingItem) {
existingItem.quantity = payload.quantity;
} else {
cart.push(payload);
}
localStorage.setItem('cart', JSON.stringify(cart));
return cart;
}
function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
let cart = JSON.parse(localStorage.getItem('cart')) || [];
const itemIndex = cart.findIndex(item =>
item.itemName === itemName &&
item.instructions === instructions &&
JSON.stringify(item.addons) === JSON.stringify(addons)
);
if (itemIndex !== -1) {
if (quantityToRemove >= cart[itemIndex].quantity) {
cart.splice(itemIndex, 1);
} else {
cart[itemIndex].quantity -= quantityToRemove;
}
}
localStorage.setItem('cart', JSON.stringify(cart));
return cart;
}
function getCartLocalStorage() {
return JSON.parse(localStorage.getItem('cart')) || [];
}
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
function updateModalPrice() {
const selectedAddOns = Array.from(
document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
).map(addon => parseFloat(addon.getAttribute('data-price')) || 0);
const totalAddOnPrice = selectedAddOns.reduce((sum, price) => sum + price, 0);
const totalPrice = baseItemPrice + totalAddOnPrice;
document.getElementById('modal-price').innerText = `$${totalPrice.toFixed(2)}`;
}
function updateSoftDrinkQuantity(delta) {
const quantityInput = document.getElementById('soft-drink-quantity');
let currentQuantity = parseInt(quantityInput.value) || 1;
currentQuantity = Math.max(1, currentQuantity + delta);
quantityInput.value = currentQuantity;
}
function showSoftDrinkModal(button) {
currentSoftDrinkButton = button;
const buttonContainer = button.closest('.button-container');
const itemName = buttonContainer.getAttribute('data-item-name');
const itemPrice = buttonContainer.getAttribute('data-item-price');
const itemImage = buttonContainer.getAttribute('data-item-image');
document.getElementById('soft-drink-name').textContent = itemName;
document.getElementById('soft-drink-price').textContent = `${itemPrice}`;
document.getElementById('soft-drink-quantity').value = '1';
document.getElementById('soft-drink-image').src = itemImage || '/static/placeholder.jpg';
const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
modal.show();
}
function addSoftDrinkToCart() {
if (!currentSoftDrinkButton) return;
const buttonContainer = currentSoftDrinkButton.closest('.button-container');
const quantity = parseInt(document.getElementById('soft-drink-quantity').value) || 1;
const itemName = buttonContainer.getAttribute('data-item-name');
const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
const itemImage = buttonContainer.getAttribute('data-item-image');
const section = buttonContainer.getAttribute('data-item-section');
const selectedCategory = buttonContainer.getAttribute('data-item-category');
const cartPayload = {
itemName: itemName,
itemPrice: itemPrice,
itemImage: itemImage,
section: section,
category: selectedCategory,
addons: [],
instructions: '',
quantity: quantity
};
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(cartPayload)
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateCartUI(data.cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
modal.hide();
} else {
console.error('Failed to add item to cart:', data.error);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
modal.hide();
}
})
.catch(err => {
console.error('Error adding item to cart:', err);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
modal.hide();
});
}
function updateCartUI(cart) {
if (!Array.isArray(cart)) {
console.error('Invalid cart data:', cart);
return;
}
let totalQuantity = 0;
cart.forEach(item => {
totalQuantity += item.quantity;
});
const cartItemCount = document.getElementById('cart-item-count');
if (cartItemCount) {
cartItemCount.innerText = totalQuantity;
cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
}
}
function showItemDetails(name, price, image, description, section, selectedCategory) {
document.getElementById('modal-name').innerText = name;
baseItemPrice = parseFloat(price) || 0;
document.getElementById('modal-price').innerText = `$${baseItemPrice.toFixed(2)}`;
const modalImg = document.getElementById('modal-img');
modalImg.src = image || '/static/placeholder.jpg';
document.getElementById('modal-description').innerText = description || 'No description available.';
document.getElementById('addons-list').innerHTML = '';
document.getElementById('addons-list').classList.add('addon-loading');
document.getElementById('modal-instructions').value = '';
const modalSectionEl = document.getElementById('modal-section');
modalSectionEl.setAttribute('data-section', section);
modalSectionEl.setAttribute('data-category', selectedCategory);
document.getElementById('quantityInput').value = 1;
fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
.then(response => response.json())
.then(data => {
const addonsList = document.getElementById('addons-list');
addonsList.classList.remove('addon-loading');
addonsList.innerHTML = '';
if (!data.success || !data.addons || data.addons.length === 0) {
addonsList.innerHTML = '<p>No customization options available.</p>';
return;
}
data.addons.forEach(addon => {
const sectionDiv = document.createElement('div');
sectionDiv.classList.add('addon-section');
const title = document.createElement('h6');
title.innerText = addon.name;
sectionDiv.appendChild(title);
const optionsContainer = document.createElement('div');
optionsContainer.classList.add('addon-options');
addon.options.forEach((option, index) => {
const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
const listItem = document.createElement('div');
listItem.classList.add('form-check');
listItem.innerHTML = `
<input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}"
aria-label="Select ${option} for ${addon.name}">
<label class="form-check-label" for="${optionId}">
${option} ${addon.extra_charge ? `<span class="extra-charge">($${addon.extra_charge_amount.toFixed(2)})</span>` : ''}
</label>
`;
optionsContainer.appendChild(listItem);
});
sectionDiv.appendChild(optionsContainer);
addonsList.appendChild(sectionDiv);
});
const addonSections = addonsList.querySelectorAll('.addon-section');
addonSections.forEach(section => {
const title = section.querySelector('h6');
const options = section.querySelector('.addon-options');
title.addEventListener('click', () => {
section.classList.toggle('collapsed');
options.classList.toggle('collapsed');
});
});
document.querySelectorAll('.addon-option').forEach(checkbox => {
checkbox.addEventListener('change', updateModalPrice);
});
document.querySelectorAll('.addon-option').forEach(checkbox => {
checkbox.addEventListener('change', function () {
const groupName = this.getAttribute('data-group');
const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"].includes(groupName);
if (!isMultiSelectGroup && this.checked) {
document.querySelectorAll(`.addon-option[data-group="${groupName}"]`).forEach(otherCheckbox => {
if (otherCheckbox !== this) {
otherCheckbox.checked = false;
}
});
}
});
});
})
.catch(err => {
console.error('Error fetching add-ons:', err);
document.getElementById('addons-list').classList.remove('addon-loading');
document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
});
}
function addToCartFromModal() {
if (isProcessingRequest) return;
isProcessingRequest = true;
const modalSectionEl = document.getElementById('modal-section');
const section = modalSectionEl.getAttribute('data-section');
const selectedCategory = modalSectionEl.getAttribute('data-category');
const itemName = document.getElementById('modal-name').innerText;
const itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', '')) || 0;
const itemImage = document.getElementById('modal-img').src;
const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
const instructions = document.getElementById('modal-instructions').value;
const selectedAddOns = Array.from(
document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
).map(addon => ({
name: addon.getAttribute('data-name'),
price: parseFloat(addon.getAttribute('data-price')) || 0
}));
if (!itemName || isNaN(itemPrice) || !section || !itemImage || quantity < 1) {
console.error('Invalid cart item data:', { itemName, itemPrice, section, itemImage, quantity });
alert('Invalid item data. Please try again.');
isProcessingRequest = false;
return;
}
const cartPayload = {
itemName: itemName,
itemPrice: itemPrice,
itemImage: itemImage,
section: section,
category: selectedCategory,
addons: selectedAddOns,
instructions: instructions,
quantity: quantity
};
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(cartPayload)
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateCartUI(data.cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
modal.hide();
} else {
console.error('Failed to add item to cart:', data.error);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
modal.hide();
}
})
.catch(err => {
console.error('Error adding item to cart:', err);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
modal.hide();
})
.finally(() => {
isProcessingRequest = false;
});
}
function handleToggle(source) {
const form = document.getElementById("filter-form");
const veg = document.getElementById("veg-toggle");
const custom = document.getElementById("category-CustomizedDish");
if (source === 'veg') {
if (veg.checked) {
custom.checked = false;
}
} else if (source === 'custom') {
if (custom.checked) {
veg.checked = false;
}
}
if (!custom.checked && !veg.checked) {
custom.checked = false;
}
form.submit();
}
document.addEventListener('DOMContentLoaded', function () {
const avatarContainer = document.querySelector('.avatar-dropdown-container');
const dropdownMenu = document.querySelector('.dropdown-menu');
avatarContainer.addEventListener('click', function (event) {
event.stopPropagation();
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
});
document.addEventListener('click', function (event) {
if (!avatarContainer.contains(event.target)) {
dropdownMenu.style.display = 'none';
}
});
const dropdownItems = document.querySelectorAll('.dropdown-item');
dropdownItems.forEach(item => {
item.addEventListener('click', function () {
dropdownMenu.style.display = 'none';
});
});
const searchBar = document.getElementById('searchBar');
searchBar.addEventListener('click', function () {
window.location.href = '/search';
});
const selectedItem = localStorage.getItem('selectedItem');
if (selectedItem) {
try {
const { name, section } = JSON.parse(selectedItem);
const menuCards = document.querySelectorAll('.menu-card');
let targetCard = null;
let buttonContainer = null;
menuCards.forEach(card => {
const itemName = card.getAttribute('data-item-name');
const itemSection = card.getAttribute('data-item-section');
if (itemName === name && itemSection === section) {
targetCard = card;
buttonContainer = card.querySelector('.button-container');
card.classList.add('highlighted');
card.scrollIntoView({ behavior: 'smooth', block: 'center' });
const toggleLink = card.querySelector('.toggle-details');
if (toggleLink) {
toggleLink.click();
}
}
});
if (buttonContainer) {
if (section === 'Soft Drinks') {
showSoftDrinkModal(buttonContainer.querySelector('.add-to-cart-btn'));
} else {
const name = buttonContainer.getAttribute('data-item-name');
const price = buttonContainer.getAttribute('data-item-price');
const image = buttonContainer.getAttribute('data-item-image2');
const description = buttonContainer.getAttribute('data-item-description');
const category = buttonContainer.getAttribute('data-item-category');
showItemDetails(name, price, image, description, section, category);
const modal = new bootstrap.Modal(document.getElementById('itemModal'));
modal.show();
}
}
} catch (err) {
console.error('Error parsing selected item:', err);
}
localStorage.removeItem('selectedItem');
}
const menuCards = document.querySelectorAll('.menu-card');
const menuVideos = document.querySelectorAll('.menu-video');
const cardObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, {
root: null,
rootMargin: '0px',
threshold: 0.1
});
const videoObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const video = entry.target;
const src = video.getAttribute('data-src');
if (src && !video.querySelector('source[src="' + src + '"]')) {
const nextSibling = video.nextElementSibling;
if (nextSibling && nextSibling.tagName === 'SOURCE') {
nextSibling.src = src;
} else {
const source = video.querySelector('source');
if (source) {
source.src = src;
}
}
video.load();
}
video.classList.add('loaded');
observer.unobserve(video);
}
});
}, {
root: null,
rootMargin: '200px',
threshold: 0.01
});
menuCards.forEach(card => cardObserver.observe(card));
menuVideos.forEach(video => videoObserver.observe(video));
const toggleLinks = document.querySelectorAll('.toggle-details');
toggleLinks.forEach(link => {
link.addEventListener('click', function () {
const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
const detailsDiv = document.getElementById(`details-${itemName}`);
const isCurrentlyShown = detailsDiv.classList.contains('show');
document.querySelectorAll('.item-details.show').forEach(otherDetails => {
if (otherDetails !== detailsDiv) {
otherDetails.classList.remove('show');
const otherLink = document.querySelector(`.toggle-details[data-item-name="${otherDetails.id.replace('details-', '').replace(/-/g, ' ')}"]`);
if (otherLink) {
otherLink.innerText = 'Show Details';
}
}
});
if (!isCurrentlyShown) {
detailsDiv.classList.add('show');
this.innerText = 'Hide Details';
} else {
detailsDiv.classList.remove('show');
this.innerText = 'Show Details';
}
});
});
const descriptionTextarea = document.getElementById('custom-dish-description');
const descriptionSuggestions = document.getElementById('descriptionSuggestions');
if (descriptionTextarea && descriptionSuggestions) {
let usedIngredients = new Set();
function updateUsedIngredients() {
const inputText = descriptionTextarea.value.trim();
usedIngredients.clear();
if (inputText) {
const words = inputText.split(/,\s*/).map(word => word.trim());
words.forEach(word => {
if (word && ingredientsList.includes(word)) {
usedIngredients.add(word);
}
});
}
}
descriptionTextarea.addEventListener('input', function () {
const inputText = this.value.trim();
const words = inputText.split(/,\s*/);
const lastWord = words[words.length - 1].trim().toLowerCase();
descriptionSuggestions.innerHTML = '';
descriptionSuggestions.style.display = 'none';
updateUsedIngredients();
if (lastWord) {
const filteredIngredients = ingredientsList.filter(ingredient =>
ingredient.toLowerCase().includes(lastWord) && !usedIngredients.has(ingredient)
);
if (filteredIngredients.length > 0) {
filteredIngredients.forEach(ingredient => {
const suggestionDiv = document.createElement('div');
suggestionDiv.classList.add('suggestion-item');
suggestionDiv.innerText = ingredient;
suggestionDiv.addEventListener('click', function () {
const currentValue = descriptionTextarea.value;
const lastCommaIndex = currentValue.lastIndexOf(',');
const baseText = lastCommaIndex !== -1 ? currentValue.substring(0, lastCommaIndex + 1) : '';
descriptionTextarea.value = baseText + (baseText ? ' ' : '') + ingredient + ', ';
descriptionSuggestions.style.display = 'none';
descriptionTextarea.focus();
updateUsedIngredients();
});
descriptionSuggestions.appendChild(suggestionDiv);
});
descriptionSuggestions.style.display = 'block';
}
}
});
document.addEventListener('click', function (event) {
if (!descriptionTextarea.contains(event.target) && !descriptionSuggestions.contains(event.target)) {
descriptionSuggestions.style.display = 'none';
}
});
}
fetch('/cart/get')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
updateCartUI(data.cart);
} else {
console.error('Failed to fetch cart:', data.error);
const cart = getCartLocalStorage();
updateCartUI(cart);
}
})
.catch(err => {
console.error('Error fetching cart:', err);
const cart = getCartLocalStorage();
updateCartUI(cart);
});
const preloadedVideos = document.querySelectorAll('link[rel="preload"][as="video"]');
preloadedVideos.forEach(link => {
const video = document.createElement('video');
video.src = link.href;
video.preload = 'auto';
});
const decreaseBtn = document.getElementById('decreaseQuantity');
const increaseBtn = document.getElementById('increaseQuantity');
const quantityInput = document.getElementById('quantityInput');
decreaseBtn.addEventListener('click', function () {
let quantity = parseInt(quantityInput.value) || 1;
quantity = Math.max(1, quantity - 1);
quantityInput.value = quantity;
});
increaseBtn.addEventListener('click', function () {
let quantity = parseInt(quantityInput.value) || 1;
quantity += 1;
quantityInput.value = quantity;
});
});
</script>
</body>
</html>