Merge pull request #75 from Sea-Haven-Industries/fix/form-mobile-layout
Some checks are pending
Deploy / deploy (push) Waiting to run

fix(form): improve mobile layout for order form and admin toolbar
This commit is contained in:
Adam Moussa 2026-07-30 16:26:41 -04:00 • committed by GitHub
commit 3fe6e74557
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -248,13 +248,14 @@ async function submitOrder() {
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Sea Haven — Meal Order ({week})</title>
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAA7EAAAOxAGVKw4bAAABX0lEQVRYhe3TPWsUURjF8d+dnSxhoxA1xEJnQQsJGbBTrIIIvoEDNqkNiJ9BrPwI4jeY2kmVoKWkSVALK6MgwWLsJIWIBBFZLGaLTTLrJrX3X96X5znnPPcSiUQikf+dcHAhr+qLuIrT2MV77Owv9ycWy6u6i3tnOu5maTg/FUzjOz5gHe/KImsXkFf1ZTzH9ZbaNdbwElvby/0fwzsJFnANN3uJO/00zJ5MxmrcwqOyyD7uE5BX9Q08xh5O4BL+ZXkXvzQp9RKcS4OzaUukh9nDg7LIVkcFGI04r2pDZw+xgrlx1U516KdB93DnGhvYxBd8w08M0MXnssgmCx7O9RZuYzEw30sszATpXCeY2R/3AC/wTMu420gnHbgyHeY1sb3FH9wfc28DT8oiezOx63EE4DeeYqllb4BXGsevj+L4IEd4M6ysf6X5HUu4oEniE9bKIts5dtdIJBKJREb4C8ngTD+C9DtvAAAAAElFTkSuQmCC">
<style>
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
body {{ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f7; color: #1d1d1f; }}
.container {{ max-width: 800px; margin: 0 auto; padding: 16px; }}
body {{ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f7; color: #1d1d1f; padding-bottom: calc(80px + env(safe-area-inset-bottom, 0px)); }}
.container {{ max-width: 1400px; margin: 0 auto; padding: 16px; }}
#meals-list {{ display: grid; grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); gap: 12px; }}
header {{ background: #1a1a2e; color: #fff; padding: 24px 16px; text-align: center; margin-bottom: 24px; border-radius: 12px; }}
header h1 {{ font-size: 1.5rem; margin-bottom: 4px; }}
header p {{ font-size: 0.85rem; opacity: 0.8; }}
@ -265,7 +266,7 @@ header p {{ font-size: 0.85rem; opacity: 0.8; }}
.filters {{ display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }}
.filters button {{ padding: 6px 14px; border: 1px solid #d1d5db; border-radius: 20px; background: #fff; font-size: 0.8rem; cursor: pointer; transition: all 0.2s; }}
.filters button.active {{ background: #1a1a2e; color: #fff; border-color: #1a1a2e; }}
.meal-card {{ background: #fff; border-radius: 12px; padding: 12px; margin-bottom: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); display: flex; gap: 12px; align-items: center; }}
.meal-card {{ background: #fff; border-radius: 12px; padding: 12px; margin-bottom: 0; box-shadow: 0 1px 3px rgba(0,0,0,0.08); display: flex; gap: 12px; align-items: center; }}
.meal-img {{ width: 80px; height: 80px; border-radius: 8px; object-fit: cover; flex-shrink: 0; }}
.meal-info {{ flex: 1; min-width: 0; }}
.meal-name {{ font-weight: 600; font-size: 0.95rem; margin-bottom: 2px; }}
@ -279,8 +280,8 @@ header p {{ font-size: 0.85rem; opacity: 0.8; }}
.qty-control button:last-child {{ border-radius: 0 8px 8px 0; }}
.qty-control .qty {{ width: 36px; height: 32px; text-align: center; border: 1px solid #d1d5db; border-left: 0; border-right: 0; font-size: 0.95rem; font-weight: 600; }}
.meal-card.selected {{ border: 2px solid #1a1a2e; }}
.sticky-footer {{ position: fixed; bottom: 0; left: 0; right: 0; background: #fff; border-top: 1px solid #e5e7eb; padding: 12px 16px; box-shadow: 0 -2px 8px rgba(0,0,0,0.1); z-index: 100; }}
.sticky-footer .inner {{ max-width: 800px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center; }}
.sticky-footer {{ position: fixed; bottom: 0; left: 0; right: 0; background: #fff; border-top: 1px solid #e5e7eb; padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px)); box-shadow: 0 -2px 8px rgba(0,0,0,0.1); z-index: 100; }}
.sticky-footer .inner {{ max-width: 1400px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center; }}
.total {{ font-size: 1.1rem; font-weight: 700; }}
.submit-btn {{ background: #1a1a2e; color: #fff; border: none; padding: 12px 32px; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: opacity 0.2s; }}
.submit-btn:disabled {{ opacity: 0.4; cursor: not-allowed; }}
@ -290,18 +291,19 @@ header p {{ font-size: 0.85rem; opacity: 0.8; }}
.back-btn {{ background: transparent; color: #1a1a2e; border: 2px solid #1a1a2e; padding: 12px 32px; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all 0.2s; margin-top: 20px; }}
.back-btn:hover {{ background: #1a1a2e; color: #fff; }}
.duplicate-warning {{ background: #fef3c7; color: #92400e; padding: 10px 16px; border-radius: 8px; margin-bottom: 20px; font-size: 0.9rem; text-align: center; font-weight: 500; border: 1px solid #fcd34d; }}
.meal-desc {{ font-size: 0.8rem; color: #6b7280; margin-bottom: 4px; }}
.meal-desc {{ font-size: 0.8rem; color: #6b7280; margin-bottom: 4px; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }}
.search-bar {{ width: 100%; padding: 10px 12px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 1rem; margin-bottom: 16px; }}
body {{ padding-bottom: 80px; }}
.closed-banner {{ background: #fee2e2; color: #991b1b; padding: 16px; border-radius: 8px; margin-bottom: 20px; text-align: center; font-weight: 600; font-size: 1rem; }}
@media (min-width: 768px) {{
.container {{ max-width: 1100px; }}
#meals-list {{ display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }}
#meals-list .meal-card {{ margin-bottom: 0; }}
@media (max-width: 480px) {{
.meal-card {{ display: grid; grid-template-columns: 80px minmax(0, 1fr); align-items: start; }}
.meal-card.no-image {{ grid-template-columns: minmax(0, 1fr); }}
.qty-control {{ grid-column: 1 / -1; justify-content: center; }}
}}
@media (min-width: 1200px) {{
.container {{ max-width: 1400px; }}
#meals-list {{ grid-template-columns: repeat(3, 1fr); }}
@media (pointer: coarse) {{
.qty-control button {{ width: 44px; height: 44px; }}
.qty-control .qty {{ width: 44px; height: 44px; }}
.edit-qty button {{ width: 44px; height: 44px; }}
.edit-qty span {{ width: 44px; height: 44px; line-height: 44px; }}
}}
.discount-banner {{ background: #dcfce7; color: #15803d; padding: 10px 16px; border-radius: 8px; margin-bottom: 20px; font-size: 0.85rem; text-align: center; font-weight: 500; }}
.price-retail {{ text-decoration: line-through; color: #9ca3af; font-size: 0.75rem; margin-right: 4px; }}
@ -321,6 +323,15 @@ body {{ padding-bottom: 80px; }}
.admin-panel {{ background: #fff; border-radius: 12px; padding: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }}
.admin-header {{ display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; flex-wrap: wrap; gap: 12px; }}
.admin-header h2 {{ font-size: 1.2rem; font-weight: 700; margin: 0; }}
.admin-toolbar {{ display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }}
.admin-toolbar select {{ padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 0.9rem; }}
.admin-toolbar-btn {{ margin: 0; padding: 8px 16px; font-size: 0.85rem; background: #1a1a2e; color: #fff; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; }}
.admin-toolbar-btn:disabled {{ opacity: 0.4; cursor: not-allowed; }}
.admin-toolbar .back-btn {{ margin: 0; padding: 8px 16px; font-size: 0.85rem; }}
@media (max-width: 600px) {{
.admin-toolbar {{ width: 100%; }}
.admin-toolbar > * {{ flex: 1 1 100%; }}
}}
.admin-stats {{ font-size: 0.9rem; color: #6b7280; margin-bottom: 16px; }}
.admin-stats strong {{ color: #1d1d1f; }}
.admin-table-wrap {{ overflow-x: auto; }}
@ -416,11 +427,11 @@ body {{ padding-bottom: 80px; }}
<div class="admin-panel">
<div class="admin-header">
<h2>Order Admin</h2>
<div style="display:flex;gap:8px;align-items:center;">
<select id="admin-week" onchange="loadWeekOrders(this.value)" style="padding:8px 12px;border:1px solid #d1d5db;border-radius:8px;font-size:0.9rem;"></select>
<button id="admin-download-btn" onclick="downloadOrderList()" style="margin:0;padding:8px 16px;font-size:0.85rem;background:#1a1a2e;color:#fff;border:none;border-radius:8px;cursor:pointer;font-weight:600;" disabled>Download order list</button>
<button id="admin-pdf-btn" onclick="downloadSummaryPdf()" style="margin:0;padding:8px 16px;font-size:0.85rem;background:#1a1a2e;color:#fff;border:none;border-radius:8px;cursor:pointer;font-weight:600;">Download summary PDF</button>
<button onclick="hideAdmin()" class="back-btn" style="margin:0;padding:8px 16px;font-size:0.85rem;">Back to Menu</button>
<div class="admin-toolbar">
<select id="admin-week" onchange="loadWeekOrders(this.value)"></select>
<button id="admin-download-btn" class="admin-toolbar-btn" onclick="downloadOrderList()" disabled>Download order list</button>
<button id="admin-pdf-btn" class="admin-toolbar-btn" onclick="downloadSummaryPdf()">Download summary PDF</button>
<button onclick="hideAdmin()" class="back-btn">Back to Menu</button>
</div>
</div>
<div id="admin-stats" class="admin-stats"></div>
@ -541,7 +552,7 @@ function renderMeals() {{
const qty = quantities[i] || 0;
const card = document.createElement('div');
card.className = 'meal-card' + (qty > 0 ? ' selected' : '');
card.className = 'meal-card' + (qty > 0 ? ' selected' : '') + (meal.image_url ? '' : ' no-image');
let tagsHtml = '';
if (meal.is_new) tagsHtml += '<span class="new">NEW</span>';