Update templates/menu.html
Browse files- templates/menu.html +106 -33
templates/menu.html
CHANGED
@@ -146,6 +146,13 @@
|
|
146 |
color: white;
|
147 |
font-size: 20px;
|
148 |
font-weight: bold;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
}
|
150 |
.dropdown-menu {
|
151 |
position: absolute;
|
@@ -653,6 +660,17 @@
|
|
653 |
50% { transform: scale(1.1); }
|
654 |
100% { transform: scale(1); }
|
655 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
656 |
@media (max-width: 576px) {
|
657 |
.fixed-top-bar {
|
658 |
height: 60px;
|
@@ -845,13 +863,11 @@
|
|
845 |
</style>
|
846 |
</head>
|
847 |
<body>
|
848 |
-
|
849 |
<div class="fixed-top-bar">
|
850 |
<div class="avatar-dropdown-container">
|
851 |
<div class="avatar-icon" id="avatarIcon">
|
852 |
{% if user_image %}
|
853 |
-
<img src="{{ user_image }}" alt="User Avatar" class="avatar-image"
|
854 |
-
style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;">
|
855 |
{% else %}
|
856 |
<span>{{ first_letter }}</span>
|
857 |
{% endif %}
|
@@ -880,6 +896,24 @@
|
|
880 |
</div>
|
881 |
</div>
|
882 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
883 |
<form method="get" action="/menu" class="text-center mb-4" id="categoryForm">
|
884 |
<label class="form-label fw-bold">Select a Category:</label>
|
885 |
<div class="category-buttons">
|
@@ -1254,28 +1288,67 @@
|
|
1254 |
const avatarIcon = document.getElementById('avatarIcon');
|
1255 |
const avatarUpload = document.getElementById('avatarUpload');
|
1256 |
const deleteAvatar = document.getElementById('deleteAvatar');
|
|
|
1257 |
|
1258 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1259 |
avatarIcon.addEventListener('click', function(event) {
|
1260 |
event.stopPropagation();
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
dropdownMenu.style.display = 'none';
|
1268 |
}
|
1269 |
});
|
1270 |
|
1271 |
-
// Handle image upload
|
1272 |
avatarUpload.addEventListener('change', function(event) {
|
1273 |
const file = event.target.files[0];
|
1274 |
if (file) {
|
|
|
|
|
|
|
|
|
|
|
|
|
1275 |
const reader = new FileReader();
|
1276 |
reader.onload = function(e) {
|
1277 |
const base64Image = e.target.result;
|
1278 |
-
|
1279 |
fetch('/upload_avatar', {
|
1280 |
method: 'POST',
|
1281 |
headers: {
|
@@ -1286,21 +1359,15 @@
|
|
1286 |
.then(response => response.json())
|
1287 |
.then(data => {
|
1288 |
if (data.success) {
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
img.style.cssText = 'width: 100%; height: 100%; object-fit: cover; border-radius: 50%;';
|
1299 |
-
avatarIcon.innerHTML = '';
|
1300 |
-
avatarIcon.appendChild(img);
|
1301 |
-
}
|
1302 |
-
// Add delete option if not present
|
1303 |
-
if (!document.getElementById('deleteAvatar')) {
|
1304 |
const deleteItem = document.createElement('div');
|
1305 |
deleteItem.className = 'dropdown-item delete-item';
|
1306 |
deleteItem.id = 'deleteAvatar';
|
@@ -1334,11 +1401,7 @@
|
|
1334 |
.then(response => response.json())
|
1335 |
.then(data => {
|
1336 |
if (data.success) {
|
1337 |
-
|
1338 |
-
const firstLetter = "{{ first_letter }}";
|
1339 |
-
avatarIcon.innerHTML = `<span>${firstLetter}</span>`;
|
1340 |
-
// Remove delete option
|
1341 |
-
deleteElement.remove();
|
1342 |
dropdownMenu.style.display = 'none';
|
1343 |
} else {
|
1344 |
alert('Failed to delete image: ' + (data.error || 'Unknown error'));
|
@@ -1356,6 +1419,16 @@
|
|
1356 |
addDeleteListener(deleteAvatar);
|
1357 |
}
|
1358 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1359 |
const menuCards = document.querySelectorAll('.menu-card');
|
1360 |
const menuVideos = document.querySelectorAll('.menu-video');
|
1361 |
const cardObserver = new IntersectionObserver((entries, observer) => {
|
|
|
146 |
color: white;
|
147 |
font-size: 20px;
|
148 |
font-weight: bold;
|
149 |
+
position: relative;
|
150 |
+
}
|
151 |
+
.avatar-icon img {
|
152 |
+
width: 100%;
|
153 |
+
height: 100%;
|
154 |
+
object-fit: cover;
|
155 |
+
border-radius: 50%;
|
156 |
}
|
157 |
.dropdown-menu {
|
158 |
position: absolute;
|
|
|
660 |
50% { transform: scale(1.1); }
|
661 |
100% { transform: scale(1); }
|
662 |
}
|
663 |
+
.avatar-modal .modal-content {
|
664 |
+
border-radius: 15px;
|
665 |
+
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
666 |
+
}
|
667 |
+
.avatar-modal .modal-body img {
|
668 |
+
max-width: 100%;
|
669 |
+
max-height: 80vh;
|
670 |
+
border-radius: 10px;
|
671 |
+
margin: 0 auto;
|
672 |
+
display: block;
|
673 |
+
}
|
674 |
@media (max-width: 576px) {
|
675 |
.fixed-top-bar {
|
676 |
height: 60px;
|
|
|
863 |
</style>
|
864 |
</head>
|
865 |
<body>
|
|
|
866 |
<div class="fixed-top-bar">
|
867 |
<div class="avatar-dropdown-container">
|
868 |
<div class="avatar-icon" id="avatarIcon">
|
869 |
{% if user_image %}
|
870 |
+
<img src="{{ user_image }}" alt="User Avatar" class="avatar-image">
|
|
|
871 |
{% else %}
|
872 |
<span>{{ first_letter }}</span>
|
873 |
{% endif %}
|
|
|
896 |
</div>
|
897 |
</div>
|
898 |
|
899 |
+
<!-- Avatar View Modal -->
|
900 |
+
<div class="modal fade avatar-modal" id="avatarViewModal" tabindex="-1" aria-labelledby="avatarViewModalLabel" aria-hidden="true">
|
901 |
+
<div class="modal-dialog modal-dialog-centered">
|
902 |
+
<div class="modal-content">
|
903 |
+
<div class="modal-header">
|
904 |
+
<h5 class="modal-title" id="avatarViewModalLabel">View Avatar</h5>
|
905 |
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
906 |
+
</div>
|
907 |
+
<div class="modal-body">
|
908 |
+
<img id="avatarModalImage" src="" alt="Avatar Image" class="img-fluid">
|
909 |
+
</div>
|
910 |
+
<div class="modal-footer">
|
911 |
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
912 |
+
</div>
|
913 |
+
</div>
|
914 |
+
</div>
|
915 |
+
</div>
|
916 |
+
|
917 |
<form method="get" action="/menu" class="text-center mb-4" id="categoryForm">
|
918 |
<label class="form-label fw-bold">Select a Category:</label>
|
919 |
<div class="category-buttons">
|
|
|
1288 |
const avatarIcon = document.getElementById('avatarIcon');
|
1289 |
const avatarUpload = document.getElementById('avatarUpload');
|
1290 |
const deleteAvatar = document.getElementById('deleteAvatar');
|
1291 |
+
const avatarModalImage = document.getElementById('avatarModalImage');
|
1292 |
|
1293 |
+
// Load avatar from localStorage if available
|
1294 |
+
function loadAvatar() {
|
1295 |
+
const savedAvatar = localStorage.getItem('userAvatar');
|
1296 |
+
if (savedAvatar && !document.querySelector('.avatar-image')) {
|
1297 |
+
const img = document.createElement('img');
|
1298 |
+
img.src = savedAvatar;
|
1299 |
+
img.alt = 'User Avatar';
|
1300 |
+
img.className = 'avatar-image';
|
1301 |
+
img.style.cssText = 'width: 100%; height: 100%; object-fit: cover; border-radius: 50%;';
|
1302 |
+
avatarIcon.innerHTML = '';
|
1303 |
+
avatarIcon.appendChild(img);
|
1304 |
+
if (!deleteAvatar) {
|
1305 |
+
const deleteItem = document.createElement('div');
|
1306 |
+
deleteItem.className = 'dropdown-item delete-item';
|
1307 |
+
deleteItem.id = 'deleteAvatar';
|
1308 |
+
deleteItem.innerText = 'Delete Image';
|
1309 |
+
dropdownMenu.insertBefore(deleteItem, dropdownMenu.querySelector('.dropdown-item:last-child'));
|
1310 |
+
addDeleteListener(deleteItem);
|
1311 |
+
}
|
1312 |
+
}
|
1313 |
+
}
|
1314 |
+
|
1315 |
+
// Save avatar to localStorage
|
1316 |
+
function saveAvatar(imageUrl) {
|
1317 |
+
localStorage.setItem('userAvatar', imageUrl);
|
1318 |
+
}
|
1319 |
+
|
1320 |
+
// Clear avatar from localStorage
|
1321 |
+
function clearAvatar() {
|
1322 |
+
localStorage.removeItem('userAvatar');
|
1323 |
+
avatarIcon.innerHTML = `<span>{{ first_letter }}</span>`;
|
1324 |
+
if (deleteAvatar) deleteAvatar.remove();
|
1325 |
+
}
|
1326 |
+
|
1327 |
+
// Avatar click handler (show modal or dropdown)
|
1328 |
avatarIcon.addEventListener('click', function(event) {
|
1329 |
event.stopPropagation();
|
1330 |
+
const avatarImg = this.querySelector('.avatar-image');
|
1331 |
+
if (avatarImg) {
|
1332 |
+
avatarModalImage.src = avatarImg.src;
|
1333 |
+
new bootstrap.Modal(document.getElementById('avatarViewModal')).show();
|
1334 |
+
} else {
|
1335 |
+
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
|
|
|
1336 |
}
|
1337 |
});
|
1338 |
|
1339 |
+
// Handle image upload with 5MB limit
|
1340 |
avatarUpload.addEventListener('change', function(event) {
|
1341 |
const file = event.target.files[0];
|
1342 |
if (file) {
|
1343 |
+
const maxSize = 5 * 1024 * 1024; // 5MB in bytes
|
1344 |
+
if (file.size > maxSize) {
|
1345 |
+
alert('Image size must not exceed 5MB.');
|
1346 |
+
this.value = '';
|
1347 |
+
return;
|
1348 |
+
}
|
1349 |
const reader = new FileReader();
|
1350 |
reader.onload = function(e) {
|
1351 |
const base64Image = e.target.result;
|
|
|
1352 |
fetch('/upload_avatar', {
|
1353 |
method: 'POST',
|
1354 |
headers: {
|
|
|
1359 |
.then(response => response.json())
|
1360 |
.then(data => {
|
1361 |
if (data.success) {
|
1362 |
+
const img = document.createElement('img');
|
1363 |
+
img.src = data.image;
|
1364 |
+
img.alt = 'User Avatar';
|
1365 |
+
img.className = 'avatar-image';
|
1366 |
+
img.style.cssText = 'width: 100%; height: 100%; object-fit: cover; border-radius: 50%;';
|
1367 |
+
avatarIcon.innerHTML = '';
|
1368 |
+
avatarIcon.appendChild(img);
|
1369 |
+
saveAvatar(data.image);
|
1370 |
+
if (!deleteAvatar) {
|
|
|
|
|
|
|
|
|
|
|
|
|
1371 |
const deleteItem = document.createElement('div');
|
1372 |
deleteItem.className = 'dropdown-item delete-item';
|
1373 |
deleteItem.id = 'deleteAvatar';
|
|
|
1401 |
.then(response => response.json())
|
1402 |
.then(data => {
|
1403 |
if (data.success) {
|
1404 |
+
clearAvatar();
|
|
|
|
|
|
|
|
|
1405 |
dropdownMenu.style.display = 'none';
|
1406 |
} else {
|
1407 |
alert('Failed to delete image: ' + (data.error || 'Unknown error'));
|
|
|
1419 |
addDeleteListener(deleteAvatar);
|
1420 |
}
|
1421 |
|
1422 |
+
// Load avatar on page load
|
1423 |
+
loadAvatar();
|
1424 |
+
|
1425 |
+
// Close dropdown when clicking outside
|
1426 |
+
document.addEventListener('click', function(event) {
|
1427 |
+
if (!avatarContainer.contains(event.target)) {
|
1428 |
+
dropdownMenu.style.display = 'none';
|
1429 |
+
}
|
1430 |
+
});
|
1431 |
+
|
1432 |
const menuCards = document.querySelectorAll('.menu-card');
|
1433 |
const menuVideos = document.querySelectorAll('.menu-video');
|
1434 |
const cardObserver = new IntersectionObserver((entries, observer) => {
|