/* global React, ReactDOM */
/* After-dinner menu page — clones the IT menu but removes the items below.
Reuses MenuPage view logic from menu-page.jsx by re-implementing the
render here (kept tiny) and feeding it a filtered MENU_DATA. */
const REMOVED_ITEMS = new Set([
"Tagliere Drop's",
"Greek Salad",
"Varazze",
"Les Sables d'Or",
"Big Kahuna",
"Anchor Burger",
"Floater",
"Tuberiding",
"The Truck",
]);
(() => {
const src = window.MENU_DATA;
// Deep-clone food sections, filter items, drop empty sections so the tab
// bar doesn't show categories that no longer have content.
const filteredFood = src.food
.map(s => ({ ...s, items: s.items.filter(it => !REMOVED_ITEMS.has(it.n)) }))
.filter(s => s.items.length > 0);
window.MENU_DATA = { ...src, food: filteredFood };
})();
const { useState, useEffect, useRef } = React;
function SectionTitle({ kicker, title, sub }) {
return (
{kicker}
{title}
{sub ?
{sub}
: null}
);
}
function ChiliIcon() {
return (
);
}
function MenuItem({ item, twoPrice }) {
return (
{item.n}
{item.spicy ? : null}
{item.d ?
{item.d}
: null}
{item.a ? (
{item.a.split(",").map((x, i) => (
{x.trim()}
))}
) : null}
{twoPrice ? (
<>
{item.p1}
{item.p2}
>
) : (
€ {item.p}
)}
);
}
function MenuSection({ section }) {
const twoPrice = !!section.twoPrice || !!section.headers;
return (
{section.headers && (
{section.headers[0]}
{section.headers[1]}
)}
{section.items.map((it, i) => )}
);
}
function MenuTabBar({ tabs, activeId, onSelect }) {
const ref = useRef(null);
useEffect(() => {
const el = ref.current?.querySelector(`[data-tab="${activeId}"]`);
if (el) el.scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" });
}, [activeId]);
return (
);
}
function MenuAfterDinnerPage() {
const data = window.MENU_DATA;
const [mode, setMode] = useState("food"); // After-dinner: default to food
const sections = mode === "food" ? data.food : data.drinks;
const [activeId, setActiveId] = useState(sections[0].id);
useEffect(() => {
const observer = new IntersectionObserver(
entries => {
const visible = entries
.filter(e => e.isIntersecting)
.sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
if (visible.length) setActiveId(visible[0].target.id);
},
{ rootMargin: "-30% 0px -60% 0px", threshold: 0 }
);
sections.forEach(s => {
const el = document.getElementById(s.id);
if (el) observer.observe(el);
});
return () => observer.disconnect();
}, [mode, sections]);
const onSelectTab = id => {
const el = document.getElementById(id);
if (el) {
const y = el.getBoundingClientRect().top + window.scrollY - 160;
window.scrollTo({ top: y, behavior: "smooth" });
}
};
const onModeSwitch = next => {
setMode(next);
setActiveId((next === "food" ? data.food : data.drinks)[0].id);
window.scrollTo({ top: 0, behavior: "smooth" });
};
return (
Drop's Fregene · Dopo cena
After
dinner.
tirare tardi
Avviso
Nel weekend ti chiederemo il saldo del conto subito dopo aver ordinato.
Grazie per la comprensione!
Cocktail, distillati, birre alla spina e qualcosa da sgranocchiare
fino alle due di notte. Si parte dai drinks, ma la cucina resta aperta.
{sections.map(s => )}
);
}
ReactDOM.createRoot(document.getElementById("root")).render();