Roasted Bean Deploy commited on
Commit Β·
63c7397
1
Parent(s): a3cc6f8
π° βΉ prices + dynamic cafe name everywhere
Browse files- data/menu.json +14 -14
- public/admin.html +2 -2
- public/index.html +4 -3
- public/js/admin.js +5 -0
- public/js/main.js +18 -1
- public/js/order.js +11 -6
- server.js +1 -1
data/menu.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
"id": "a1b2c3d4-0001",
|
| 7 |
"name": "Cappuccino",
|
| 8 |
"description": "Rich espresso topped with velvety steamed milk foam. A timeless Italian favorite.",
|
| 9 |
-
"price":
|
| 10 |
"category": "coffee",
|
| 11 |
"image": "https://images.unsplash.com/photo-1572442388796-11668a67e53d?w=160&h=160&fit=crop&auto=format",
|
| 12 |
"available": true,
|
|
@@ -16,7 +16,7 @@
|
|
| 16 |
"id": "a1b2c3d4-0002",
|
| 17 |
"name": "Vanilla Latte",
|
| 18 |
"description": "Smooth espresso with steamed milk and house-made vanilla syrup.",
|
| 19 |
-
"price":
|
| 20 |
"category": "coffee",
|
| 21 |
"image": "https://images.unsplash.com/photo-1461023058943-07fcbe16d735?w=160&h=160&fit=crop&auto=format",
|
| 22 |
"available": true,
|
|
@@ -26,7 +26,7 @@
|
|
| 26 |
"id": "a1b2c3d4-0003",
|
| 27 |
"name": "Cold Brew",
|
| 28 |
"description": "Slow-steeped for 18 hours \u2014 smooth, bold, and naturally sweet. Served over ice.",
|
| 29 |
-
"price":
|
| 30 |
"category": "coffee",
|
| 31 |
"image": "https://images.unsplash.com/photo-1517701550927-30cf4ba1dba5?w=160&h=160&fit=crop&auto=format",
|
| 32 |
"available": true,
|
|
@@ -36,7 +36,7 @@
|
|
| 36 |
"id": "a1b2c3d4-0004",
|
| 37 |
"name": "Caramel Macchiato",
|
| 38 |
"description": "Layered espresso and milk with a buttery caramel drizzle.",
|
| 39 |
-
"price":
|
| 40 |
"category": "coffee",
|
| 41 |
"image": "https://images.unsplash.com/photo-1485808191679-5f86510681a2?w=160&h=160&fit=crop&auto=format",
|
| 42 |
"available": true,
|
|
@@ -46,7 +46,7 @@
|
|
| 46 |
"id": "a1b2c3d4-0005",
|
| 47 |
"name": "Mocha",
|
| 48 |
"description": "Decadent chocolate meets bold espresso, crowned with whipped cream.",
|
| 49 |
-
"price":
|
| 50 |
"category": "coffee",
|
| 51 |
"image": "https://images.unsplash.com/photo-1578314675249-a6910f80cc4e?w=160&h=160&fit=crop&auto=format",
|
| 52 |
"available": true,
|
|
@@ -56,7 +56,7 @@
|
|
| 56 |
"id": "a1b2c3d4-0006",
|
| 57 |
"name": "Matcha Latte",
|
| 58 |
"description": "Ceremonial-grade Japanese matcha whisked with steamed oat milk.",
|
| 59 |
-
"price":
|
| 60 |
"category": "tea",
|
| 61 |
"image": "https://images.unsplash.com/photo-1536256263959-770b48d82b0a?w=160&h=160&fit=crop&auto=format",
|
| 62 |
"available": true,
|
|
@@ -66,7 +66,7 @@
|
|
| 66 |
"id": "a1b2c3d4-0007",
|
| 67 |
"name": "Earl Grey",
|
| 68 |
"description": "Fragrant black tea with bergamot. Served in a pot with a lemon twist.",
|
| 69 |
-
"price":
|
| 70 |
"category": "tea",
|
| 71 |
"image": "https://images.unsplash.com/photo-1594631252845-29fc4cc8cde9?w=160&h=160&fit=crop&auto=format",
|
| 72 |
"available": true,
|
|
@@ -76,7 +76,7 @@
|
|
| 76 |
"id": "a1b2c3d4-0008",
|
| 77 |
"name": "Chamomile Honey",
|
| 78 |
"description": "Soothing chamomile blossoms with a drizzle of local wildflower honey.",
|
| 79 |
-
"price":
|
| 80 |
"category": "tea",
|
| 81 |
"image": "https://images.unsplash.com/photo-1576092768241-dec231879fc3?w=160&h=160&fit=crop&auto=format",
|
| 82 |
"available": true,
|
|
@@ -86,7 +86,7 @@
|
|
| 86 |
"id": "a1b2c3d4-0009",
|
| 87 |
"name": "Butter Croissant",
|
| 88 |
"description": "Flaky, golden, and impossibly buttery. Baked fresh every morning.",
|
| 89 |
-
"price":
|
| 90 |
"category": "pastries",
|
| 91 |
"image": "https://images.unsplash.com/photo-1623334044303-241021148842?w=160&h=160&fit=crop&auto=format",
|
| 92 |
"available": true,
|
|
@@ -96,7 +96,7 @@
|
|
| 96 |
"id": "a1b2c3d4-0010",
|
| 97 |
"name": "Blueberry Muffin",
|
| 98 |
"description": "Tender crumb studded with wild blueberries and a streusel top.",
|
| 99 |
-
"price":
|
| 100 |
"category": "pastries",
|
| 101 |
"image": "https://images.unsplash.com/photo-1607958996333-41aef7caefaa?w=160&h=160&fit=crop&auto=format",
|
| 102 |
"available": true,
|
|
@@ -106,7 +106,7 @@
|
|
| 106 |
"id": "a1b2c3d4-0011",
|
| 107 |
"name": "Cinnamon Roll",
|
| 108 |
"description": "Soft, gooey, and generously swirled with cinnamon-brown sugar. Topped with cream cheese frosting.",
|
| 109 |
-
"price":
|
| 110 |
"category": "pastries",
|
| 111 |
"image": "https://images.unsplash.com/photo-1509365465985-25d11c17e812?w=160&h=160&fit=crop&auto=format",
|
| 112 |
"available": true,
|
|
@@ -116,7 +116,7 @@
|
|
| 116 |
"id": "a1b2c3d4-0012",
|
| 117 |
"name": "Avocado Toast",
|
| 118 |
"description": "Sourdough topped with smashed avocado, cherry tomatoes, feta, and chili flakes.",
|
| 119 |
-
"price":
|
| 120 |
"category": "food",
|
| 121 |
"image": "https://images.unsplash.com/photo-1541519227354-08fa5d50c44d?w=160&h=160&fit=crop&auto=format",
|
| 122 |
"available": true,
|
|
@@ -126,7 +126,7 @@
|
|
| 126 |
"id": "a1b2c3d4-0013",
|
| 127 |
"name": "Caprese Panini",
|
| 128 |
"description": "Fresh mozzarella, tomato, and basil pressed on ciabatta with balsamic glaze.",
|
| 129 |
-
"price":
|
| 130 |
"category": "food",
|
| 131 |
"image": "https://images.unsplash.com/photo-1509722747041-616f39b57569?w=160&h=160&fit=crop&auto=format",
|
| 132 |
"available": true,
|
|
@@ -136,7 +136,7 @@
|
|
| 136 |
"id": "a1b2c3d4-0014",
|
| 137 |
"name": "A\u00e7a\u00ed Bowl",
|
| 138 |
"description": "Blended a\u00e7a\u00ed with granola, banana, strawberries, coconut, and a drizzle of honey.",
|
| 139 |
-
"price":
|
| 140 |
"category": "food",
|
| 141 |
"image": "https://images.unsplash.com/photo-1590301157890-4810ed352733?w=160&h=160&fit=crop&auto=format",
|
| 142 |
"available": true,
|
|
|
|
| 6 |
"id": "a1b2c3d4-0001",
|
| 7 |
"name": "Cappuccino",
|
| 8 |
"description": "Rich espresso topped with velvety steamed milk foam. A timeless Italian favorite.",
|
| 9 |
+
"price": 375,
|
| 10 |
"category": "coffee",
|
| 11 |
"image": "https://images.unsplash.com/photo-1572442388796-11668a67e53d?w=160&h=160&fit=crop&auto=format",
|
| 12 |
"available": true,
|
|
|
|
| 16 |
"id": "a1b2c3d4-0002",
|
| 17 |
"name": "Vanilla Latte",
|
| 18 |
"description": "Smooth espresso with steamed milk and house-made vanilla syrup.",
|
| 19 |
+
"price": 415,
|
| 20 |
"category": "coffee",
|
| 21 |
"image": "https://images.unsplash.com/photo-1461023058943-07fcbe16d735?w=160&h=160&fit=crop&auto=format",
|
| 22 |
"available": true,
|
|
|
|
| 26 |
"id": "a1b2c3d4-0003",
|
| 27 |
"name": "Cold Brew",
|
| 28 |
"description": "Slow-steeped for 18 hours \u2014 smooth, bold, and naturally sweet. Served over ice.",
|
| 29 |
+
"price": 395,
|
| 30 |
"category": "coffee",
|
| 31 |
"image": "https://images.unsplash.com/photo-1517701550927-30cf4ba1dba5?w=160&h=160&fit=crop&auto=format",
|
| 32 |
"available": true,
|
|
|
|
| 36 |
"id": "a1b2c3d4-0004",
|
| 37 |
"name": "Caramel Macchiato",
|
| 38 |
"description": "Layered espresso and milk with a buttery caramel drizzle.",
|
| 39 |
+
"price": 455,
|
| 40 |
"category": "coffee",
|
| 41 |
"image": "https://images.unsplash.com/photo-1485808191679-5f86510681a2?w=160&h=160&fit=crop&auto=format",
|
| 42 |
"available": true,
|
|
|
|
| 46 |
"id": "a1b2c3d4-0005",
|
| 47 |
"name": "Mocha",
|
| 48 |
"description": "Decadent chocolate meets bold espresso, crowned with whipped cream.",
|
| 49 |
+
"price": 435,
|
| 50 |
"category": "coffee",
|
| 51 |
"image": "https://images.unsplash.com/photo-1578314675249-a6910f80cc4e?w=160&h=160&fit=crop&auto=format",
|
| 52 |
"available": true,
|
|
|
|
| 56 |
"id": "a1b2c3d4-0006",
|
| 57 |
"name": "Matcha Latte",
|
| 58 |
"description": "Ceremonial-grade Japanese matcha whisked with steamed oat milk.",
|
| 59 |
+
"price": 455,
|
| 60 |
"category": "tea",
|
| 61 |
"image": "https://images.unsplash.com/photo-1536256263959-770b48d82b0a?w=160&h=160&fit=crop&auto=format",
|
| 62 |
"available": true,
|
|
|
|
| 66 |
"id": "a1b2c3d4-0007",
|
| 67 |
"name": "Earl Grey",
|
| 68 |
"description": "Fragrant black tea with bergamot. Served in a pot with a lemon twist.",
|
| 69 |
+
"price": 310,
|
| 70 |
"category": "tea",
|
| 71 |
"image": "https://images.unsplash.com/photo-1594631252845-29fc4cc8cde9?w=160&h=160&fit=crop&auto=format",
|
| 72 |
"available": true,
|
|
|
|
| 76 |
"id": "a1b2c3d4-0008",
|
| 77 |
"name": "Chamomile Honey",
|
| 78 |
"description": "Soothing chamomile blossoms with a drizzle of local wildflower honey.",
|
| 79 |
+
"price": 290,
|
| 80 |
"category": "tea",
|
| 81 |
"image": "https://images.unsplash.com/photo-1576092768241-dec231879fc3?w=160&h=160&fit=crop&auto=format",
|
| 82 |
"available": true,
|
|
|
|
| 86 |
"id": "a1b2c3d4-0009",
|
| 87 |
"name": "Butter Croissant",
|
| 88 |
"description": "Flaky, golden, and impossibly buttery. Baked fresh every morning.",
|
| 89 |
+
"price": 310,
|
| 90 |
"category": "pastries",
|
| 91 |
"image": "https://images.unsplash.com/photo-1623334044303-241021148842?w=160&h=160&fit=crop&auto=format",
|
| 92 |
"available": true,
|
|
|
|
| 96 |
"id": "a1b2c3d4-0010",
|
| 97 |
"name": "Blueberry Muffin",
|
| 98 |
"description": "Tender crumb studded with wild blueberries and a streusel top.",
|
| 99 |
+
"price": 350,
|
| 100 |
"category": "pastries",
|
| 101 |
"image": "https://images.unsplash.com/photo-1607958996333-41aef7caefaa?w=160&h=160&fit=crop&auto=format",
|
| 102 |
"available": true,
|
|
|
|
| 106 |
"id": "a1b2c3d4-0011",
|
| 107 |
"name": "Cinnamon Roll",
|
| 108 |
"description": "Soft, gooey, and generously swirled with cinnamon-brown sugar. Topped with cream cheese frosting.",
|
| 109 |
+
"price": 415,
|
| 110 |
"category": "pastries",
|
| 111 |
"image": "https://images.unsplash.com/photo-1509365465985-25d11c17e812?w=160&h=160&fit=crop&auto=format",
|
| 112 |
"available": true,
|
|
|
|
| 116 |
"id": "a1b2c3d4-0012",
|
| 117 |
"name": "Avocado Toast",
|
| 118 |
"description": "Sourdough topped with smashed avocado, cherry tomatoes, feta, and chili flakes.",
|
| 119 |
+
"price": 790,
|
| 120 |
"category": "food",
|
| 121 |
"image": "https://images.unsplash.com/photo-1541519227354-08fa5d50c44d?w=160&h=160&fit=crop&auto=format",
|
| 122 |
"available": true,
|
|
|
|
| 126 |
"id": "a1b2c3d4-0013",
|
| 127 |
"name": "Caprese Panini",
|
| 128 |
"description": "Fresh mozzarella, tomato, and basil pressed on ciabatta with balsamic glaze.",
|
| 129 |
+
"price": 870,
|
| 130 |
"category": "food",
|
| 131 |
"image": "https://images.unsplash.com/photo-1509722747041-616f39b57569?w=160&h=160&fit=crop&auto=format",
|
| 132 |
"available": true,
|
|
|
|
| 136 |
"id": "a1b2c3d4-0014",
|
| 137 |
"name": "A\u00e7a\u00ed Bowl",
|
| 138 |
"description": "Blended a\u00e7a\u00ed with granola, banana, strawberries, coconut, and a drizzle of honey.",
|
| 139 |
+
"price": 915,
|
| 140 |
"category": "food",
|
| 141 |
"image": "https://images.unsplash.com/photo-1590301157890-4810ed352733?w=160&h=160&fit=crop&auto=format",
|
| 142 |
"available": true,
|
public/admin.html
CHANGED
|
@@ -30,7 +30,7 @@
|
|
| 30 |
<header class="topbar">
|
| 31 |
<div class="topbar-inner">
|
| 32 |
<div class="topbar-brand">
|
| 33 |
-
<a href="/" class="topbar-logo" target="_blank">The Roasted Bean</a>
|
| 34 |
<span class="topbar-badge">Admin</span>
|
| 35 |
</div>
|
| 36 |
<nav class="topbar-nav" id="topbarNav">
|
|
@@ -96,7 +96,7 @@
|
|
| 96 |
<form id="infoForm" class="form-block">
|
| 97 |
<div class="field">
|
| 98 |
<label for="infoName">Cafe name</label>
|
| 99 |
-
<input type="text" id="infoName" placeholder="
|
| 100 |
</div>
|
| 101 |
<div class="field">
|
| 102 |
<label for="infoTagline">Tagline</label>
|
|
|
|
| 30 |
<header class="topbar">
|
| 31 |
<div class="topbar-inner">
|
| 32 |
<div class="topbar-brand">
|
| 33 |
+
<a href="/" class="topbar-logo" target="_blank" data-cafe-name>The Roasted Bean</a>
|
| 34 |
<span class="topbar-badge">Admin</span>
|
| 35 |
</div>
|
| 36 |
<nav class="topbar-nav" id="topbarNav">
|
|
|
|
| 96 |
<form id="infoForm" class="form-block">
|
| 97 |
<div class="field">
|
| 98 |
<label for="infoName">Cafe name</label>
|
| 99 |
+
<input type="text" id="infoName" placeholder="Cafe Name">
|
| 100 |
</div>
|
| 101 |
<div class="field">
|
| 102 |
<label for="infoTagline">Tagline</label>
|
public/index.html
CHANGED
|
@@ -14,7 +14,7 @@
|
|
| 14 |
<!-- Navigation -->
|
| 15 |
<nav class="nav" id="nav">
|
| 16 |
<div class="nav-inner">
|
| 17 |
-
<a href="#" class="nav-logo">The Roasted Bean</a>
|
| 18 |
<div class="nav-links">
|
| 19 |
<a href="#menu">Menu</a>
|
| 20 |
<a href="/order">Order</a>
|
|
@@ -68,7 +68,7 @@
|
|
| 68 |
<div class="about-layout">
|
| 69 |
<div class="about-text">
|
| 70 |
<h2 class="section-title">From farm to cup, we pay attention at every step</h2>
|
| 71 |
-
<p>The Roasted Bean started in 2018 with a 3-kilo roaster in a garage and a conviction that coffee could be better. Today we operate a full cafe and roastery in Portland's east side, but the conviction hasn't changed.</p>
|
| 72 |
<p>We buy directly from producers in Ethiopia, Colombia, Guatemala, and beyond β paying well above commodity prices because quality farming deserves quality compensation. Each lot is roasted to highlight its unique character, not to conform to a house style.</p>
|
| 73 |
<div class="about-figures">
|
| 74 |
<div class="figure">
|
|
@@ -106,6 +106,7 @@
|
|
| 106 |
src="https://images.unsplash.com/photo-1501339847302-ac426a4a7cbb?w=1920&q=85&fit=crop&crop=center"
|
| 107 |
alt="Interior of The Roasted Bean cafe"
|
| 108 |
loading="lazy"
|
|
|
|
| 109 |
/>
|
| 110 |
</div>
|
| 111 |
<div class="visit-content">
|
|
@@ -149,7 +150,7 @@
|
|
| 149 |
<div class="container">
|
| 150 |
<div class="footer-grid">
|
| 151 |
<div>
|
| 152 |
-
<p class="footer-name">The Roasted Bean</p>
|
| 153 |
<p class="footer-tagline">Specialty coffee roasters<br>Portland, Oregon</p>
|
| 154 |
</div>
|
| 155 |
<div class="footer-links">
|
|
|
|
| 14 |
<!-- Navigation -->
|
| 15 |
<nav class="nav" id="nav">
|
| 16 |
<div class="nav-inner">
|
| 17 |
+
<a href="#" class="nav-logo" data-cafe-name>The Roasted Bean</a>
|
| 18 |
<div class="nav-links">
|
| 19 |
<a href="#menu">Menu</a>
|
| 20 |
<a href="/order">Order</a>
|
|
|
|
| 68 |
<div class="about-layout">
|
| 69 |
<div class="about-text">
|
| 70 |
<h2 class="section-title">From farm to cup, we pay attention at every step</h2>
|
| 71 |
+
<p><span class="cafe-name-ref">The Roasted Bean</span> started in 2018 with a 3-kilo roaster in a garage and a conviction that coffee could be better. Today we operate a full cafe and roastery in Portland's east side, but the conviction hasn't changed.</p>
|
| 72 |
<p>We buy directly from producers in Ethiopia, Colombia, Guatemala, and beyond β paying well above commodity prices because quality farming deserves quality compensation. Each lot is roasted to highlight its unique character, not to conform to a house style.</p>
|
| 73 |
<div class="about-figures">
|
| 74 |
<div class="figure">
|
|
|
|
| 106 |
src="https://images.unsplash.com/photo-1501339847302-ac426a4a7cbb?w=1920&q=85&fit=crop&crop=center"
|
| 107 |
alt="Interior of The Roasted Bean cafe"
|
| 108 |
loading="lazy"
|
| 109 |
+
id="visitImage"
|
| 110 |
/>
|
| 111 |
</div>
|
| 112 |
<div class="visit-content">
|
|
|
|
| 150 |
<div class="container">
|
| 151 |
<div class="footer-grid">
|
| 152 |
<div>
|
| 153 |
+
<p class="footer-name" data-cafe-name>The Roasted Bean</p>
|
| 154 |
<p class="footer-tagline">Specialty coffee roasters<br>Portland, Oregon</p>
|
| 155 |
</div>
|
| 156 |
<div class="footer-links">
|
public/js/admin.js
CHANGED
|
@@ -60,6 +60,11 @@ async function setupDashboard() {
|
|
| 60 |
async function loadMenuData() {
|
| 61 |
const res = await fetch('/api/menu');
|
| 62 |
menuData = await res.json();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
}
|
| 64 |
|
| 65 |
// ββ Navigation ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 60 |
async function loadMenuData() {
|
| 61 |
const res = await fetch('/api/menu');
|
| 62 |
menuData = await res.json();
|
| 63 |
+
// Update cafe name everywhere in admin
|
| 64 |
+
if (menuData.info?.name) {
|
| 65 |
+
document.title = `Admin β ${menuData.info.name}`;
|
| 66 |
+
document.querySelectorAll('[data-cafe-name]').forEach(el => el.textContent = menuData.info.name);
|
| 67 |
+
}
|
| 68 |
}
|
| 69 |
|
| 70 |
// ββ Navigation ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
public/js/main.js
CHANGED
|
@@ -63,6 +63,23 @@ function populateHero(info) {
|
|
| 63 |
if (info.name) {
|
| 64 |
document.getElementById('cafeName').textContent = info.name;
|
| 65 |
document.title = `${info.name} β Specialty Coffee Roasters`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
}
|
| 67 |
if (info.address) {
|
| 68 |
const el = document.getElementById('cafeAddressSmall');
|
|
@@ -151,7 +168,7 @@ function buildMenu(items, categories) {
|
|
| 151 |
</div>
|
| 152 |
<div class="menu-card-header">
|
| 153 |
<h3 class="menu-card-name">${escapeHtml(item.name)}</h3>
|
| 154 |
-
<span class="menu-card-price">$
|
| 155 |
</div>
|
| 156 |
<span class="menu-card-label">Tasting</span>
|
| 157 |
<p class="menu-card-description">${escapeHtml(item.description)}</p>
|
|
|
|
| 63 |
if (info.name) {
|
| 64 |
document.getElementById('cafeName').textContent = info.name;
|
| 65 |
document.title = `${info.name} β Specialty Coffee Roasters`;
|
| 66 |
+
// Update all name references throughout the page
|
| 67 |
+
const nameEls = document.querySelectorAll('[data-cafe-name]');
|
| 68 |
+
nameEls.forEach(el => { el.textContent = info.name; });
|
| 69 |
+
// Update copyright
|
| 70 |
+
const copyEl = document.querySelector('.footer-copy');
|
| 71 |
+
if (copyEl) copyEl.textContent = `Β© 2024 ${info.name}`;
|
| 72 |
+
// Update about text references
|
| 73 |
+
const aboutRefs = document.querySelectorAll('.cafe-name-ref');
|
| 74 |
+
aboutRefs.forEach(el => { el.textContent = info.name; });
|
| 75 |
+
// Update visit image alt text
|
| 76 |
+
const visitImg = document.getElementById('visitImage');
|
| 77 |
+
if (visitImg && info.name) {
|
| 78 |
+
visitImg.alt = `Interior of ${info.name} cafe`;
|
| 79 |
+
}
|
| 80 |
+
// Update footer name
|
| 81 |
+
const footerName = document.querySelector('.footer-name');
|
| 82 |
+
if (footerName) footerName.textContent = info.name;
|
| 83 |
}
|
| 84 |
if (info.address) {
|
| 85 |
const el = document.getElementById('cafeAddressSmall');
|
|
|
|
| 168 |
</div>
|
| 169 |
<div class="menu-card-header">
|
| 170 |
<h3 class="menu-card-name">${escapeHtml(item.name)}</h3>
|
| 171 |
+
<span class="menu-card-price">βΉ${item.price.toFixed(0)}</span>
|
| 172 |
</div>
|
| 173 |
<span class="menu-card-label">Tasting</span>
|
| 174 |
<p class="menu-card-description">${escapeHtml(item.description)}</p>
|
public/js/order.js
CHANGED
|
@@ -25,6 +25,11 @@ async function init() {
|
|
| 25 |
const tablesData = await tablesRes.json();
|
| 26 |
tablesCount = tablesData.tables || 0;
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
// No table from URL β show table selector
|
| 29 |
if (!tableNumber) {
|
| 30 |
document.getElementById('tableDisplay').style.display = 'none';
|
|
@@ -95,7 +100,7 @@ function renderItems(catId = 'all') {
|
|
| 95 |
<div class="ord-item-name">${esc(item.name)}</div>
|
| 96 |
<div class="ord-item-desc">${esc(item.description || '')}</div>
|
| 97 |
</div>
|
| 98 |
-
<div class="ord-item-price">$
|
| 99 |
<button class="ord-item-add" ${!item.available ? 'disabled' : ''}>${qty > 0 ? qty : '+'}</button>
|
| 100 |
</div>
|
| 101 |
`;
|
|
@@ -153,14 +158,14 @@ function renderCart() {
|
|
| 153 |
<div class="cart-item">
|
| 154 |
<div class="cart-item-info">
|
| 155 |
<div class="cart-item-name">${esc(c.name)}</div>
|
| 156 |
-
<div class="cart-item-meta">$
|
| 157 |
</div>
|
| 158 |
<div class="cart-item-qty">
|
| 159 |
<button class="cart-qty-btn" data-action="minus" data-mid="${c.mid}">β</button>
|
| 160 |
<span class="cart-qty-num">${c.qty}</span>
|
| 161 |
<button class="cart-qty-btn" data-action="plus" data-mid="${c.mid}">+</button>
|
| 162 |
</div>
|
| 163 |
-
<div class="cart-item-price">$
|
| 164 |
<button class="cart-item-remove" data-action="remove" data-mid="${c.mid}">β</button>
|
| 165 |
</div>
|
| 166 |
`).join('');
|
|
@@ -177,7 +182,7 @@ function renderCart() {
|
|
| 177 |
});
|
| 178 |
}
|
| 179 |
|
| 180 |
-
document.getElementById('cartTotal').textContent = `$
|
| 181 |
document.getElementById('cartCount').textContent = cart.reduce((s, c) => s + c.qty, 0);
|
| 182 |
document.getElementById('cartBadge').style.display = cart.length > 0 ? '' : 'none';
|
| 183 |
|
|
@@ -211,12 +216,12 @@ async function loadLiveOrders() {
|
|
| 211 |
</div>
|
| 212 |
<ul class="live-order-items">
|
| 213 |
${o.items.map(i => i.mid
|
| 214 |
-
? `<li><span>${i.qty}Γ ${esc(i.name)}</span> <span>$
|
| 215 |
: `<li class="lo-custom">"${esc(i.text)}"</li>`
|
| 216 |
).join('')}
|
| 217 |
</ul>
|
| 218 |
${o.note ? `<p class="live-order-note">Note: ${esc(o.note)}</p>` : ''}
|
| 219 |
-
<p class="live-order-total">$
|
| 220 |
</div>
|
| 221 |
`).join('');
|
| 222 |
} catch { /* silently fail β customer-facing */ }
|
|
|
|
| 25 |
const tablesData = await tablesRes.json();
|
| 26 |
tablesCount = tablesData.tables || 0;
|
| 27 |
|
| 28 |
+
// Update page title
|
| 29 |
+
if (menuData?.info?.name) {
|
| 30 |
+
document.title = `Order β ${menuData.info.name}`;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
// No table from URL β show table selector
|
| 34 |
if (!tableNumber) {
|
| 35 |
document.getElementById('tableDisplay').style.display = 'none';
|
|
|
|
| 100 |
<div class="ord-item-name">${esc(item.name)}</div>
|
| 101 |
<div class="ord-item-desc">${esc(item.description || '')}</div>
|
| 102 |
</div>
|
| 103 |
+
<div class="ord-item-price">βΉ${item.price.toFixed(0)}</div>
|
| 104 |
<button class="ord-item-add" ${!item.available ? 'disabled' : ''}>${qty > 0 ? qty : '+'}</button>
|
| 105 |
</div>
|
| 106 |
`;
|
|
|
|
| 158 |
<div class="cart-item">
|
| 159 |
<div class="cart-item-info">
|
| 160 |
<div class="cart-item-name">${esc(c.name)}</div>
|
| 161 |
+
<div class="cart-item-meta">βΉ${c.price.toFixed(0)} each</div>
|
| 162 |
</div>
|
| 163 |
<div class="cart-item-qty">
|
| 164 |
<button class="cart-qty-btn" data-action="minus" data-mid="${c.mid}">β</button>
|
| 165 |
<span class="cart-qty-num">${c.qty}</span>
|
| 166 |
<button class="cart-qty-btn" data-action="plus" data-mid="${c.mid}">+</button>
|
| 167 |
</div>
|
| 168 |
+
<div class="cart-item-price">βΉ${(c.price * c.qty).toFixed(0)}</div>
|
| 169 |
<button class="cart-item-remove" data-action="remove" data-mid="${c.mid}">β</button>
|
| 170 |
</div>
|
| 171 |
`).join('');
|
|
|
|
| 182 |
});
|
| 183 |
}
|
| 184 |
|
| 185 |
+
document.getElementById('cartTotal').textContent = `βΉ${total.toFixed(0)}`;
|
| 186 |
document.getElementById('cartCount').textContent = cart.reduce((s, c) => s + c.qty, 0);
|
| 187 |
document.getElementById('cartBadge').style.display = cart.length > 0 ? '' : 'none';
|
| 188 |
|
|
|
|
| 216 |
</div>
|
| 217 |
<ul class="live-order-items">
|
| 218 |
${o.items.map(i => i.mid
|
| 219 |
+
? `<li><span>${i.qty}Γ ${esc(i.name)}</span> <span>βΉ${(i.price * i.qty).toFixed(0)}</span></li>`
|
| 220 |
: `<li class="lo-custom">"${esc(i.text)}"</li>`
|
| 221 |
).join('')}
|
| 222 |
</ul>
|
| 223 |
${o.note ? `<p class="live-order-note">Note: ${esc(o.note)}</p>` : ''}
|
| 224 |
+
<p class="live-order-total">βΉ${o.total.toFixed(0)}</p>
|
| 225 |
</div>
|
| 226 |
`).join('');
|
| 227 |
} catch { /* silently fail β customer-facing */ }
|
server.js
CHANGED
|
@@ -353,6 +353,6 @@ function scheduleMidnightCleanup() {
|
|
| 353 |
|
| 354 |
// ββ Start βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 355 |
app.listen(PORT, '0.0.0.0', () => {
|
| 356 |
-
console.log(`β
|
| 357 |
});
|
| 358 |
scheduleMidnightCleanup();
|
|
|
|
| 353 |
|
| 354 |
// ββ Start βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 355 |
app.listen(PORT, '0.0.0.0', () => {
|
| 356 |
+
console.log(`β Cafe serving on 0.0.0.0:${PORT}`);
|
| 357 |
});
|
| 358 |
scheduleMidnightCleanup();
|