restaurant-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +488 -0
- package/dist/RestaurantSiteRoutes.js +23 -0
- package/dist/admin/AdminActionMenu.js +29 -0
- package/dist/admin/AdminAuthPanel.js +53 -0
- package/dist/admin/AdminBackupsDialog.js +54 -0
- package/dist/admin/AdminDraftProvider.js +10 -0
- package/dist/admin/AdminGroupsPanel.js +68 -0
- package/dist/admin/AdminItemDrawer.js +264 -0
- package/dist/admin/AdminMenuCard.js +63 -0
- package/dist/admin/AdminMenuEditor.module.css.js +209 -0
- package/dist/admin/AdminMenuGroupTabs.js +43 -0
- package/dist/admin/AdminMenuIconPicker.js +39 -0
- package/dist/admin/AdminRoutes.js +13 -0
- package/dist/admin/AdminSectionEditor.js +104 -0
- package/dist/admin/AdminTestimonialsPanel.js +214 -0
- package/dist/admin/AdminTestimonialsPanel.module.css.js +29 -0
- package/dist/admin/adminDraftContext.js +5 -0
- package/dist/admin/adminEditorUtils.js +47 -0
- package/dist/admin/adminMenuCommands.js +83 -0
- package/dist/admin/useAdminDraft.js +14 -0
- package/dist/admin/useAdminMenuDraft.js +226 -0
- package/dist/cart/CartDrawer.js +87 -0
- package/dist/cart/CartDrawer.module.css.js +47 -0
- package/dist/cart/CartProvider.js +31 -0
- package/dist/cart/cartContext.js +5 -0
- package/dist/cart/cartOrder.js +34 -0
- package/dist/cart/cartReducer.js +57 -0
- package/dist/cart/useCart.js +10 -0
- package/dist/components/Brand.js +16 -0
- package/dist/components/Brand.module.css.js +15 -0
- package/dist/components/Footer.js +19 -0
- package/dist/components/Footer.module.css.js +11 -0
- package/dist/components/Header.js +34 -0
- package/dist/components/Header.module.css.js +19 -0
- package/dist/components/Hero.js +23 -0
- package/dist/components/Hero.module.css.js +15 -0
- package/dist/components/InstagramIcon.js +27 -0
- package/dist/components/LocationsSection.js +34 -0
- package/dist/components/LocationsSection.module.css.js +17 -0
- package/dist/components/Marquee.js +10 -0
- package/dist/components/Marquee.module.css.js +9 -0
- package/dist/components/OrderIcon.js +11 -0
- package/dist/components/RatingSection.js +32 -0
- package/dist/components/RatingSection.module.css.js +19 -0
- package/dist/components/TestimonialsSection.js +73 -0
- package/dist/components/TestimonialsSection.module.css.js +37 -0
- package/dist/components/WhatsAppIcon.js +13 -0
- package/dist/config/RestaurantKitProvider.js +26 -0
- package/dist/config/siteConfigContext.js +23 -0
- package/dist/config/useOrdering.js +12 -0
- package/dist/index.js +92 -0
- package/dist/menu/localMenuApi.js +43 -0
- package/dist/menu/menuApi.js +121 -0
- package/dist/menu/menuDraftStorage.js +35 -0
- package/dist/menu/menuIcons.js +24 -0
- package/dist/menu/menuMutations.js +99 -0
- package/dist/menu/menuOrdering.js +94 -0
- package/dist/menu/menuSchema.js +4 -0
- package/dist/menu/priceFormat.js +39 -0
- package/dist/menu/useMenuData.js +38 -0
- package/dist/menu/validateMenu.js +63 -0
- package/dist/menu-browser/MenuBrowser.js +54 -0
- package/dist/menu-browser/MenuBrowser.module.css.js +153 -0
- package/dist/menu-browser/MenuCard.js +106 -0
- package/dist/menu-browser/MenuCartDrawer.js +18 -0
- package/dist/menu-browser/MenuCategoryBlock.js +45 -0
- package/dist/menu-browser/MenuItemSheet.js +132 -0
- package/dist/menu-browser/MenuLightbox.js +33 -0
- package/dist/menu-browser/MenuRow.js +43 -0
- package/dist/menu-browser/MenuSection.js +10 -0
- package/dist/menu-browser/menuItemDisplay.js +19 -0
- package/dist/menu-browser/useMediaQuery.js +19 -0
- package/dist/menu-browser/useMenuBrowserState.js +82 -0
- package/dist/menu-browser/useParkedSheet.js +32 -0
- package/dist/pages/AdminMenuEditor.js +291 -0
- package/dist/pages/AdminPreview.js +43 -0
- package/dist/pages/AdminPreview.module.css.js +9 -0
- package/dist/pages/MenuSite.js +40 -0
- package/dist/restaurant-kit.css +1 -0
- package/dist/testimonials/downscaleImage.js +14 -0
- package/dist/testimonials/testimonialMutations.js +52 -0
- package/dist/types/RestaurantSiteRoutes.d.ts +11 -0
- package/dist/types/admin/AdminActionMenu.d.ts +20 -0
- package/dist/types/admin/AdminAuthPanel.d.ts +13 -0
- package/dist/types/admin/AdminBackupsDialog.d.ts +9 -0
- package/dist/types/admin/AdminDraftProvider.d.ts +12 -0
- package/dist/types/admin/AdminGroupsPanel.d.ts +14 -0
- package/dist/types/admin/AdminItemDrawer.d.ts +16 -0
- package/dist/types/admin/AdminMenuCard.d.ts +10 -0
- package/dist/types/admin/AdminMenuGroupTabs.d.ts +11 -0
- package/dist/types/admin/AdminMenuIconPicker.d.ts +8 -0
- package/dist/types/admin/AdminRoutes.d.ts +5 -0
- package/dist/types/admin/AdminSectionEditor.d.ts +20 -0
- package/dist/types/admin/AdminTestimonialsPanel.d.ts +7 -0
- package/dist/types/admin/adminDraftContext.d.ts +2 -0
- package/dist/types/admin/adminEditorUtils.d.ts +22 -0
- package/dist/types/admin/adminMenuCommands.d.ts +73 -0
- package/dist/types/admin/useAdminDraft.d.ts +5 -0
- package/dist/types/admin/useAdminMenuDraft.d.ts +41 -0
- package/dist/types/cart/CartDrawer.d.ts +7 -0
- package/dist/types/cart/CartProvider.d.ts +4 -0
- package/dist/types/cart/cartContext.d.ts +2 -0
- package/dist/types/cart/cartOrder.d.ts +9 -0
- package/dist/types/cart/cartReducer.d.ts +36 -0
- package/dist/types/cart/cartTypes.d.ts +37 -0
- package/dist/types/cart/useCart.d.ts +1 -0
- package/dist/types/components/Brand.d.ts +5 -0
- package/dist/types/components/Footer.d.ts +1 -0
- package/dist/types/components/Header.d.ts +1 -0
- package/dist/types/components/Hero.d.ts +1 -0
- package/dist/types/components/InstagramIcon.d.ts +6 -0
- package/dist/types/components/LocationsSection.d.ts +1 -0
- package/dist/types/components/Marquee.d.ts +1 -0
- package/dist/types/components/OrderIcon.d.ts +4 -0
- package/dist/types/components/RatingSection.d.ts +1 -0
- package/dist/types/components/TestimonialsSection.d.ts +2 -0
- package/dist/types/components/WhatsAppIcon.d.ts +5 -0
- package/dist/types/config/RestaurantKitProvider.d.ts +24 -0
- package/dist/types/config/siteConfigContext.d.ts +28 -0
- package/dist/types/config/siteTypes.d.ts +50 -0
- package/dist/types/config/useOrdering.d.ts +16 -0
- package/dist/types/index.d.ts +38 -0
- package/dist/types/menu/localMenuApi.d.ts +9 -0
- package/dist/types/menu/menuApi.d.ts +68 -0
- package/dist/types/menu/menuDraftStorage.d.ts +5 -0
- package/dist/types/menu/menuIcons.d.ts +7 -0
- package/dist/types/menu/menuMutations.d.ts +13 -0
- package/dist/types/menu/menuOrdering.d.ts +38 -0
- package/dist/types/menu/menuSchema.d.ts +68 -0
- package/dist/types/menu/priceFormat.d.ts +8 -0
- package/dist/types/menu/useMenuData.d.ts +12 -0
- package/dist/types/menu/validateMenu.d.ts +16 -0
- package/dist/types/menu-browser/MenuBrowser.d.ts +6 -0
- package/dist/types/menu-browser/MenuCard.d.ts +7 -0
- package/dist/types/menu-browser/MenuCartDrawer.d.ts +5 -0
- package/dist/types/menu-browser/MenuCategoryBlock.d.ts +11 -0
- package/dist/types/menu-browser/MenuItemSheet.d.ts +10 -0
- package/dist/types/menu-browser/MenuLightbox.d.ts +9 -0
- package/dist/types/menu-browser/MenuRow.d.ts +7 -0
- package/dist/types/menu-browser/MenuSection.d.ts +1 -0
- package/dist/types/menu-browser/menuItemDisplay.d.ts +5 -0
- package/dist/types/menu-browser/useMediaQuery.d.ts +1 -0
- package/dist/types/menu-browser/useMenuBrowserState.d.ts +17 -0
- package/dist/types/menu-browser/useParkedSheet.d.ts +13 -0
- package/dist/types/pages/AdminMenuEditor.d.ts +1 -0
- package/dist/types/pages/AdminPreview.d.ts +1 -0
- package/dist/types/pages/MenuSite.d.ts +6 -0
- package/dist/types/testimonials/downscaleImage.d.ts +6 -0
- package/dist/types/testimonials/testimonialMutations.d.ts +9 -0
- package/dist/types/utils.d.ts +1 -0
- package/dist/types/worker/auth.d.ts +97 -0
- package/dist/types/worker/http.d.ts +17 -0
- package/dist/types/worker/index.d.ts +16 -0
- package/dist/types/worker/menuStorage.d.ts +94 -0
- package/dist/utils.js +6 -0
- package/dist/worker/auth.js +183 -0
- package/dist/worker/http.js +65 -0
- package/dist/worker/menuStorage.js +95 -0
- package/dist/worker.js +131 -0
- package/package.json +105 -0
- package/scripts/bootstrap-site.mjs +125 -0
- package/scripts/hash-admin-password.mjs +11 -0
- package/scripts/lib/password.mjs +72 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsxs as t, jsx as r } from "react/jsx-runtime";
|
|
2
|
+
function i({ className: e }) {
|
|
3
|
+
return /* @__PURE__ */ t(
|
|
4
|
+
"svg",
|
|
5
|
+
{
|
|
6
|
+
className: e,
|
|
7
|
+
width: "24",
|
|
8
|
+
height: "24",
|
|
9
|
+
viewBox: "0 0 24 24",
|
|
10
|
+
fill: "none",
|
|
11
|
+
stroke: "currentColor",
|
|
12
|
+
strokeWidth: "2",
|
|
13
|
+
strokeLinecap: "round",
|
|
14
|
+
strokeLinejoin: "round",
|
|
15
|
+
"aria-hidden": "true",
|
|
16
|
+
focusable: "false",
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ r("rect", { width: "20", height: "20", x: "2", y: "2", rx: "5", ry: "5" }),
|
|
19
|
+
/* @__PURE__ */ r("path", { d: "M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" }),
|
|
20
|
+
/* @__PURE__ */ r("line", { x1: "17.5", x2: "17.51", y1: "6.5", y2: "6.5" })
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
i as InstagramIcon
|
|
27
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as e, jsxs as l } from "react/jsx-runtime";
|
|
2
|
+
import { InstagramIcon as n } from "./InstagramIcon.js";
|
|
3
|
+
import r from "./LocationsSection.module.css.js";
|
|
4
|
+
import { useSiteConfig as i } from "../config/siteConfigContext.js";
|
|
5
|
+
function h() {
|
|
6
|
+
const a = i();
|
|
7
|
+
return /* @__PURE__ */ e("section", { className: `section ${r.locations}`, id: "locations", "aria-labelledby": "locations-title", children: /* @__PURE__ */ l("div", { className: "section-inner", children: [
|
|
8
|
+
/* @__PURE__ */ e("p", { className: "micro-label", children: "Location" }),
|
|
9
|
+
/* @__PURE__ */ e("h2", { id: "locations-title", children: "Come Find Us!" }),
|
|
10
|
+
/* @__PURE__ */ l("div", { className: r.row, children: [
|
|
11
|
+
/* @__PURE__ */ l("a", { className: r.card, href: a.mapsUrl, target: "_blank", rel: "noreferrer", children: [
|
|
12
|
+
/* @__PURE__ */ e("h3", { children: a.locationLabel }),
|
|
13
|
+
/* @__PURE__ */ e("p", { children: a.address }),
|
|
14
|
+
/* @__PURE__ */ e("strong", { children: "Open Maps" })
|
|
15
|
+
] }),
|
|
16
|
+
/* @__PURE__ */ l("article", { className: r.card, children: [
|
|
17
|
+
/* @__PURE__ */ e("span", { children: "TEL" }),
|
|
18
|
+
/* @__PURE__ */ e("h3", { children: a.whatsappNumber ? "Call or WhatsApp" : "Call us" }),
|
|
19
|
+
/* @__PURE__ */ l("div", { className: r.linkStack, children: [
|
|
20
|
+
/* @__PURE__ */ e("a", { href: a.phoneHref, children: a.phoneDisplay }),
|
|
21
|
+
a.whatsappNumber ? /* @__PURE__ */ e("a", { href: `https://wa.me/${a.whatsappNumber}`, target: "_blank", rel: "noreferrer", children: "Message on WhatsApp" }) : null
|
|
22
|
+
] })
|
|
23
|
+
] }),
|
|
24
|
+
/* @__PURE__ */ l("article", { className: `${r.card} ${r.accent}`, children: [
|
|
25
|
+
/* @__PURE__ */ e(n, { className: r.socialIcon }),
|
|
26
|
+
/* @__PURE__ */ e("h3", { children: a.instagramHandle }),
|
|
27
|
+
/* @__PURE__ */ e("a", { href: a.instagramUrl, target: "_blank", rel: "noreferrer", children: "Open Instagram" })
|
|
28
|
+
] })
|
|
29
|
+
] })
|
|
30
|
+
] }) });
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
h as LocationsSection
|
|
34
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const c = "_locations_106nk_1", n = "_row_106nk_14", o = "_card_106nk_23", t = "_socialIcon_106nk_57", _ = "_linkStack_106nk_100", a = "_accent_106nk_105", s = {
|
|
2
|
+
locations: c,
|
|
3
|
+
row: n,
|
|
4
|
+
card: o,
|
|
5
|
+
socialIcon: t,
|
|
6
|
+
linkStack: _,
|
|
7
|
+
accent: a
|
|
8
|
+
};
|
|
9
|
+
export {
|
|
10
|
+
a as accent,
|
|
11
|
+
o as card,
|
|
12
|
+
s as default,
|
|
13
|
+
_ as linkStack,
|
|
14
|
+
c as locations,
|
|
15
|
+
n as row,
|
|
16
|
+
t as socialIcon
|
|
17
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import s from "./Marquee.module.css.js";
|
|
3
|
+
import { useSiteConfig as t } from "../config/siteConfigContext.js";
|
|
4
|
+
function c() {
|
|
5
|
+
const { highlights: r } = t();
|
|
6
|
+
return /* @__PURE__ */ e("section", { className: s.marquee, "aria-label": "Menu highlights", children: /* @__PURE__ */ e("div", { className: s.track, children: [...r, ...r].map((i, a) => /* @__PURE__ */ e("span", { children: i }, `${i}-${a}`)) }) });
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
c as Marquee
|
|
10
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowUpRight as t } from "lucide-react";
|
|
3
|
+
import { useOrdering as n } from "../config/useOrdering.js";
|
|
4
|
+
import { WhatsAppIcon as e } from "./WhatsAppIcon.js";
|
|
5
|
+
function m({ className: r }) {
|
|
6
|
+
const i = n();
|
|
7
|
+
return i.isWhatsApp ? /* @__PURE__ */ o(e, { className: r }) : i.iconSrc ? /* @__PURE__ */ o("img", { className: r, src: i.iconSrc, alt: "", "aria-hidden": "true" }) : /* @__PURE__ */ o(t, { className: r, "aria-hidden": "true" });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
m as OrderIcon
|
|
11
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as a, jsxs as r } from "react/jsx-runtime";
|
|
2
|
+
import i from "./RatingSection.module.css.js";
|
|
3
|
+
import { useSiteConfig as l } from "../config/siteConfigContext.js";
|
|
4
|
+
const n = 5;
|
|
5
|
+
function c(e) {
|
|
6
|
+
const t = Number(e), s = Number.isFinite(t) ? Math.min(n, Math.max(0, Math.round(t))) : n;
|
|
7
|
+
return "★".repeat(s) + "☆".repeat(n - s);
|
|
8
|
+
}
|
|
9
|
+
function h() {
|
|
10
|
+
const e = l();
|
|
11
|
+
return /* @__PURE__ */ a("section", { className: `section ${i.restaurant}`, id: "restaurant", "aria-labelledby": "restaurant-title", children: /* @__PURE__ */ r("div", { className: `section-inner ${i.grid}`, children: [
|
|
12
|
+
/* @__PURE__ */ r("div", { children: [
|
|
13
|
+
/* @__PURE__ */ a("p", { className: "micro-label", children: "Customer rated" }),
|
|
14
|
+
/* @__PURE__ */ a("h2", { id: "restaurant-title", children: e.ratingHeadline })
|
|
15
|
+
] }),
|
|
16
|
+
/* @__PURE__ */ r("div", { className: i.panel, "aria-label": "Customer rating", children: [
|
|
17
|
+
/* @__PURE__ */ r("div", { className: i.score, children: [
|
|
18
|
+
/* @__PURE__ */ a("span", { children: e.rating }),
|
|
19
|
+
/* @__PURE__ */ a("div", { className: i.stars, "aria-label": e.ratingLabel, children: c(e.rating) })
|
|
20
|
+
] }),
|
|
21
|
+
/* @__PURE__ */ a("p", { className: i.copy, children: e.ratingCopy }),
|
|
22
|
+
/* @__PURE__ */ r("div", { className: i.meta, children: [
|
|
23
|
+
/* @__PURE__ */ a("span", { children: e.reviewCount }),
|
|
24
|
+
/* @__PURE__ */ a("span", { children: e.cuisineSummary }),
|
|
25
|
+
/* @__PURE__ */ a("span", { children: e.localBadge })
|
|
26
|
+
] })
|
|
27
|
+
] })
|
|
28
|
+
] }) });
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
h as RatingSection
|
|
32
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const t = "_restaurant_fztj2_1", s = "_grid_fztj2_7", _ = "_panel_fztj2_14", a = "_score_fztj2_27", r = "_stars_fztj2_41", e = "_copy_fztj2_49", o = "_meta_fztj2_56", c = {
|
|
2
|
+
restaurant: t,
|
|
3
|
+
grid: s,
|
|
4
|
+
panel: _,
|
|
5
|
+
score: a,
|
|
6
|
+
stars: r,
|
|
7
|
+
copy: e,
|
|
8
|
+
meta: o
|
|
9
|
+
};
|
|
10
|
+
export {
|
|
11
|
+
e as copy,
|
|
12
|
+
c as default,
|
|
13
|
+
s as grid,
|
|
14
|
+
o as meta,
|
|
15
|
+
_ as panel,
|
|
16
|
+
t as restaurant,
|
|
17
|
+
a as score,
|
|
18
|
+
r as stars
|
|
19
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsxs as i, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowLeft as p, ArrowRight as w, ArrowUpRight as v } from "lucide-react";
|
|
3
|
+
import { useRef as N, useState as y, useCallback as k, useEffect as C } from "react";
|
|
4
|
+
import { useSiteConfig as S } from "../config/siteConfigContext.js";
|
|
5
|
+
import { imageSrc as x } from "../menu-browser/menuItemDisplay.js";
|
|
6
|
+
import { useMenuData as $ } from "../menu/useMenuData.js";
|
|
7
|
+
import { visibleTestimonials as R, clampRating as b } from "../testimonials/testimonialMutations.js";
|
|
8
|
+
import a from "./TestimonialsSection.module.css.js";
|
|
9
|
+
const f = 5;
|
|
10
|
+
function L({ testimonial: r }) {
|
|
11
|
+
const s = b(r.rating), n = r.author.trim() || "Google reviewer";
|
|
12
|
+
return /* @__PURE__ */ i("li", { className: `${a.card} ${r.image ? "" : a.textOnly}`, children: [
|
|
13
|
+
r.image ? /* @__PURE__ */ e("div", { className: a.media, children: /* @__PURE__ */ e("img", { src: x(r.image), alt: `Photo shared by ${n}`, loading: "lazy" }) }) : null,
|
|
14
|
+
/* @__PURE__ */ i("figure", { className: a.body, children: [
|
|
15
|
+
/* @__PURE__ */ i("div", { className: a.stars, role: "img", "aria-label": `${s} out of ${f} stars`, children: [
|
|
16
|
+
"★".repeat(s),
|
|
17
|
+
/* @__PURE__ */ e("span", { "aria-hidden": "true", children: "★".repeat(f - s) })
|
|
18
|
+
] }),
|
|
19
|
+
/* @__PURE__ */ e("blockquote", { className: a.quote, children: r.text.trim() }),
|
|
20
|
+
/* @__PURE__ */ i("figcaption", { className: a.byline, children: [
|
|
21
|
+
/* @__PURE__ */ e("span", { className: a.author, children: n }),
|
|
22
|
+
r.sourceUrl ? /* @__PURE__ */ i("a", { href: r.sourceUrl, target: "_blank", rel: "noreferrer", children: [
|
|
23
|
+
"Read on Google",
|
|
24
|
+
/* @__PURE__ */ e(v, { "aria-hidden": "true" })
|
|
25
|
+
] }) : null
|
|
26
|
+
] })
|
|
27
|
+
] })
|
|
28
|
+
] });
|
|
29
|
+
}
|
|
30
|
+
function B() {
|
|
31
|
+
const r = S(), { menu: s } = $(), n = R(s), u = N(null), [m, g] = y({ back: !1, forward: !1 }), o = k(() => {
|
|
32
|
+
const t = u.current;
|
|
33
|
+
if (!t) return;
|
|
34
|
+
const l = t.scrollLeft > 4, c = t.scrollLeft + t.clientWidth < t.scrollWidth - 4;
|
|
35
|
+
g((d) => d.back === l && d.forward === c ? d : { back: l, forward: c });
|
|
36
|
+
}, []);
|
|
37
|
+
C(() => (o(), window.addEventListener("resize", o), () => window.removeEventListener("resize", o)), [o, n.length]);
|
|
38
|
+
const h = (t) => {
|
|
39
|
+
const l = u.current, c = l?.querySelector("li");
|
|
40
|
+
if (!l || !c) return;
|
|
41
|
+
const d = Number.parseFloat(getComputedStyle(l).columnGap) || 0;
|
|
42
|
+
l.scrollBy({ left: t * (c.getBoundingClientRect().width + d), behavior: "smooth" });
|
|
43
|
+
};
|
|
44
|
+
return n.length ? (
|
|
45
|
+
// Takes over the rating section's slot and anchor (`#restaurant`, linked from the header nav).
|
|
46
|
+
/* @__PURE__ */ i("section", { className: `section ${a.testimonials}`, id: "restaurant", "aria-labelledby": "reviews-title", children: [
|
|
47
|
+
/* @__PURE__ */ i("div", { className: `section-inner ${a.heading}`, children: [
|
|
48
|
+
/* @__PURE__ */ i("div", { children: [
|
|
49
|
+
r.testimonialsEyebrow ? /* @__PURE__ */ e("p", { className: "micro-label", children: r.testimonialsEyebrow }) : null,
|
|
50
|
+
/* @__PURE__ */ e("h2", { id: "reviews-title", children: r.testimonialsHeadline ?? "Our customers' cameras don't lie." })
|
|
51
|
+
] }),
|
|
52
|
+
/* @__PURE__ */ i("div", { className: a.score, "aria-label": "Customer rating", children: [
|
|
53
|
+
/* @__PURE__ */ e("span", { className: a.scoreValue, children: r.rating }),
|
|
54
|
+
/* @__PURE__ */ i("div", { children: [
|
|
55
|
+
/* @__PURE__ */ e("div", { className: a.scoreStars, role: "img", "aria-label": r.ratingLabel, children: "★".repeat(b(Number(r.rating))) }),
|
|
56
|
+
/* @__PURE__ */ e("p", { children: r.reviewCount })
|
|
57
|
+
] })
|
|
58
|
+
] })
|
|
59
|
+
] }),
|
|
60
|
+
/* @__PURE__ */ i("div", { className: `section-inner ${a.subhead}`, children: [
|
|
61
|
+
/* @__PURE__ */ e("p", { children: r.ratingCopy }),
|
|
62
|
+
m.back || m.forward ? /* @__PURE__ */ i("div", { className: a.arrows, children: [
|
|
63
|
+
/* @__PURE__ */ e("button", { type: "button", onClick: () => h(-1), disabled: !m.back, "aria-label": "Previous reviews", children: /* @__PURE__ */ e(p, { "aria-hidden": "true" }) }),
|
|
64
|
+
/* @__PURE__ */ e("button", { type: "button", onClick: () => h(1), disabled: !m.forward, "aria-label": "Next reviews", children: /* @__PURE__ */ e(w, { "aria-hidden": "true" }) })
|
|
65
|
+
] }) : null
|
|
66
|
+
] }),
|
|
67
|
+
/* @__PURE__ */ e("ul", { className: a.track, "aria-label": "Customer reviews", tabIndex: 0, ref: u, onScroll: o, children: n.map((t) => /* @__PURE__ */ e(L, { testimonial: t }, t.id)) })
|
|
68
|
+
] })
|
|
69
|
+
) : null;
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
B as TestimonialsSection
|
|
73
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const s = "_testimonials_6f34y_1", _ = "_heading_6f34y_13", t = "_score_6f34y_27", o = "_scoreValue_6f34y_40", e = "_scoreStars_6f34y_47", a = "_subhead_6f34y_63", c = "_arrows_6f34y_79", r = "_track_6f34y_114", n = "_card_6f34y_134", y = "_media_6f34y_148", f = "_body_6f34y_159", d = "_stars_6f34y_168", i = "_quote_6f34y_179", l = "_textOnly_6f34y_192", u = "_byline_6f34y_203", b = "_author_6f34y_214", h = {
|
|
2
|
+
testimonials: s,
|
|
3
|
+
heading: _,
|
|
4
|
+
score: t,
|
|
5
|
+
scoreValue: o,
|
|
6
|
+
scoreStars: e,
|
|
7
|
+
subhead: a,
|
|
8
|
+
arrows: c,
|
|
9
|
+
track: r,
|
|
10
|
+
card: n,
|
|
11
|
+
media: y,
|
|
12
|
+
body: f,
|
|
13
|
+
stars: d,
|
|
14
|
+
quote: i,
|
|
15
|
+
textOnly: l,
|
|
16
|
+
byline: u,
|
|
17
|
+
author: b
|
|
18
|
+
};
|
|
19
|
+
export {
|
|
20
|
+
c as arrows,
|
|
21
|
+
b as author,
|
|
22
|
+
f as body,
|
|
23
|
+
u as byline,
|
|
24
|
+
n as card,
|
|
25
|
+
h as default,
|
|
26
|
+
_ as heading,
|
|
27
|
+
y as media,
|
|
28
|
+
i as quote,
|
|
29
|
+
t as score,
|
|
30
|
+
e as scoreStars,
|
|
31
|
+
o as scoreValue,
|
|
32
|
+
d as stars,
|
|
33
|
+
a as subhead,
|
|
34
|
+
s as testimonials,
|
|
35
|
+
l as textOnly,
|
|
36
|
+
r as track
|
|
37
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as a } from "react/jsx-runtime";
|
|
2
|
+
function e({ className: r }) {
|
|
3
|
+
return /* @__PURE__ */ a("svg", { className: r, viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ a(
|
|
4
|
+
"path",
|
|
5
|
+
{
|
|
6
|
+
fill: "currentColor",
|
|
7
|
+
d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413Z"
|
|
8
|
+
}
|
|
9
|
+
) });
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
e as WhatsAppIcon
|
|
13
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as p } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo as s } from "react";
|
|
3
|
+
import { shouldUseLocalMenuApi as f, createLocalMenuApiClient as U } from "../menu/localMenuApi.js";
|
|
4
|
+
import { createMenuApiClient as d } from "../menu/menuApi.js";
|
|
5
|
+
import { menuDraftStorageKey as A } from "../menu/menuDraftStorage.js";
|
|
6
|
+
import { SiteConfigContext as C } from "./siteConfigContext.js";
|
|
7
|
+
function M(r, t) {
|
|
8
|
+
return r ? `${r.replace(/\/+$/, "")}/${t.replace(/^\/+/, "")}` : t;
|
|
9
|
+
}
|
|
10
|
+
function $({ config: r, seedMenu: t, api: e, menuApi: a, children: l }) {
|
|
11
|
+
const o = e?.baseUrl?.trim() ?? "", i = e?.publicMenuUrl?.trim() || M(o, "/api/menu"), n = e?.mode ?? "auto", c = s(() => {
|
|
12
|
+
const u = A(r.restaurantId), m = n === "local" || n === "auto" && f(o);
|
|
13
|
+
return {
|
|
14
|
+
config: r,
|
|
15
|
+
seedMenu: t,
|
|
16
|
+
draftStorageKey: u,
|
|
17
|
+
publicMenuUrl: i,
|
|
18
|
+
isLocalApi: m,
|
|
19
|
+
menuApi: a ?? (m ? U(t, u) : d({ apiBaseUrl: o, publicMenuUrl: i }))
|
|
20
|
+
};
|
|
21
|
+
}, [o, r, a, n, i, t]);
|
|
22
|
+
return /* @__PURE__ */ p(C.Provider, { value: c, children: l });
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
$ as RestaurantKitProvider
|
|
26
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useContext as n, createContext as u } from "react";
|
|
2
|
+
const r = u(null);
|
|
3
|
+
function e() {
|
|
4
|
+
const t = n(r);
|
|
5
|
+
if (!t) throw new Error("restaurant-kit hooks must be used inside <RestaurantKitProvider> (or <RestaurantSite>).");
|
|
6
|
+
return t;
|
|
7
|
+
}
|
|
8
|
+
function i() {
|
|
9
|
+
return e().config;
|
|
10
|
+
}
|
|
11
|
+
function s() {
|
|
12
|
+
return e().seedMenu;
|
|
13
|
+
}
|
|
14
|
+
function a() {
|
|
15
|
+
return e().menuApi;
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
r as SiteConfigContext,
|
|
19
|
+
a as useMenuApi,
|
|
20
|
+
e as useRestaurantKit,
|
|
21
|
+
s as useSeedMenu,
|
|
22
|
+
i as useSiteConfig
|
|
23
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useContext as o } from "react";
|
|
2
|
+
import { SiteConfigContext as n } from "./siteConfigContext.js";
|
|
3
|
+
function i() {
|
|
4
|
+
const e = o(n)?.config, r = e?.ordering;
|
|
5
|
+
if (r?.mode === "external")
|
|
6
|
+
return { cartEnabled: !1, isWhatsApp: !1, href: r.url, label: r.label, shortLabel: r.shortLabel ?? "Order", iconSrc: r.iconSrc };
|
|
7
|
+
const t = e?.whatsappNumber ?? "";
|
|
8
|
+
return { cartEnabled: !0, isWhatsApp: !0, href: t ? `https://wa.me/${t}` : "", label: "Order on WhatsApp", shortLabel: "Order" };
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
i as useOrdering
|
|
12
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { RestaurantSite as t } from "./RestaurantSiteRoutes.js";
|
|
3
|
+
import { RestaurantKitProvider as m } from "./config/RestaurantKitProvider.js";
|
|
4
|
+
import { useMenuApi as p, useRestaurantKit as i, useSeedMenu as f, useSiteConfig as u } from "./config/siteConfigContext.js";
|
|
5
|
+
import { useOrdering as s } from "./config/useOrdering.js";
|
|
6
|
+
import { MenuSite as M } from "./pages/MenuSite.js";
|
|
7
|
+
import { AdminMenuEditor as l } from "./pages/AdminMenuEditor.js";
|
|
8
|
+
import { AdminPreview as D } from "./pages/AdminPreview.js";
|
|
9
|
+
import { Brand as C } from "./components/Brand.js";
|
|
10
|
+
import { Footer as g } from "./components/Footer.js";
|
|
11
|
+
import { Header as v } from "./components/Header.js";
|
|
12
|
+
import { Hero as h } from "./components/Hero.js";
|
|
13
|
+
import { LocationsSection as K } from "./components/LocationsSection.js";
|
|
14
|
+
import { Marquee as L } from "./components/Marquee.js";
|
|
15
|
+
import { RatingSection as V } from "./components/RatingSection.js";
|
|
16
|
+
import { TestimonialsSection as b } from "./components/TestimonialsSection.js";
|
|
17
|
+
import { InstagramIcon as E } from "./components/InstagramIcon.js";
|
|
18
|
+
import { WhatsAppIcon as H } from "./components/WhatsAppIcon.js";
|
|
19
|
+
import { MenuBrowser as U } from "./menu-browser/MenuBrowser.js";
|
|
20
|
+
import { MenuSection as q } from "./menu-browser/MenuSection.js";
|
|
21
|
+
import { MenuCartDrawer as k } from "./menu-browser/MenuCartDrawer.js";
|
|
22
|
+
import { CartProvider as G } from "./cart/CartProvider.js";
|
|
23
|
+
import { useCart as Q } from "./cart/useCart.js";
|
|
24
|
+
import { buildWhatsAppMessage as Y, buildWhatsAppOrderUrl as Z, cartSelectionKey as _, formatVariationName as $ } from "./cart/cartOrder.js";
|
|
25
|
+
import { MenuDataProvider as er, useMenuData as or } from "./menu/useMenuData.js";
|
|
26
|
+
import { MenuApiError as nr, createMenuApiClient as mr } from "./menu/menuApi.js";
|
|
27
|
+
import { createLocalMenuApiClient as pr, shouldUseLocalMenuApi as ir } from "./menu/localMenuApi.js";
|
|
28
|
+
import { clearMenuDraft as ur, menuDraftStorageKey as xr, readMenuDraft as sr, writeMenuDraft as dr } from "./menu/menuDraftStorage.js";
|
|
29
|
+
import { menuIconOptions as cr, menuIcons as lr } from "./menu/menuIcons.js";
|
|
30
|
+
import { formatPrice as Dr, formatPriceTotal as Sr, priceFromInput as Cr, priceInputValue as Ir } from "./menu/priceFormat.js";
|
|
31
|
+
import { menuIconIds as Pr } from "./menu/menuSchema.js";
|
|
32
|
+
import { assertValidMenu as Rr, validateMenu as hr } from "./menu/validateMenu.js";
|
|
33
|
+
import { useAdminMenuDraft as Kr } from "./admin/useAdminMenuDraft.js";
|
|
34
|
+
import { AdminDraftProvider as Lr } from "./admin/AdminDraftProvider.js";
|
|
35
|
+
import { useAdminDraft as Vr, useAdminDraftContext as Wr } from "./admin/useAdminDraft.js";
|
|
36
|
+
import { applyAdminMenuCommand as Br, getAdminMenuCommandRejection as Er } from "./admin/adminMenuCommands.js";
|
|
37
|
+
export {
|
|
38
|
+
Lr as AdminDraftProvider,
|
|
39
|
+
l as AdminMenuEditor,
|
|
40
|
+
D as AdminPreview,
|
|
41
|
+
C as Brand,
|
|
42
|
+
G as CartProvider,
|
|
43
|
+
g as Footer,
|
|
44
|
+
v as Header,
|
|
45
|
+
h as Hero,
|
|
46
|
+
E as InstagramIcon,
|
|
47
|
+
K as LocationsSection,
|
|
48
|
+
L as Marquee,
|
|
49
|
+
nr as MenuApiError,
|
|
50
|
+
U as MenuBrowser,
|
|
51
|
+
k as MenuCartDrawer,
|
|
52
|
+
er as MenuDataProvider,
|
|
53
|
+
q as MenuSection,
|
|
54
|
+
M as MenuSite,
|
|
55
|
+
V as RatingSection,
|
|
56
|
+
m as RestaurantKitProvider,
|
|
57
|
+
t as RestaurantSite,
|
|
58
|
+
b as TestimonialsSection,
|
|
59
|
+
H as WhatsAppIcon,
|
|
60
|
+
Br as applyAdminMenuCommand,
|
|
61
|
+
Rr as assertValidMenu,
|
|
62
|
+
Y as buildWhatsAppMessage,
|
|
63
|
+
Z as buildWhatsAppOrderUrl,
|
|
64
|
+
_ as cartSelectionKey,
|
|
65
|
+
ur as clearMenuDraft,
|
|
66
|
+
pr as createLocalMenuApiClient,
|
|
67
|
+
mr as createMenuApiClient,
|
|
68
|
+
Dr as formatPrice,
|
|
69
|
+
Sr as formatPriceTotal,
|
|
70
|
+
$ as formatVariationName,
|
|
71
|
+
Er as getAdminMenuCommandRejection,
|
|
72
|
+
xr as menuDraftStorageKey,
|
|
73
|
+
Pr as menuIconIds,
|
|
74
|
+
cr as menuIconOptions,
|
|
75
|
+
lr as menuIcons,
|
|
76
|
+
Cr as priceFromInput,
|
|
77
|
+
Ir as priceInputValue,
|
|
78
|
+
sr as readMenuDraft,
|
|
79
|
+
ir as shouldUseLocalMenuApi,
|
|
80
|
+
Vr as useAdminDraft,
|
|
81
|
+
Wr as useAdminDraftContext,
|
|
82
|
+
Kr as useAdminMenuDraft,
|
|
83
|
+
Q as useCart,
|
|
84
|
+
p as useMenuApi,
|
|
85
|
+
or as useMenuData,
|
|
86
|
+
s as useOrdering,
|
|
87
|
+
i as useRestaurantKit,
|
|
88
|
+
f as useSeedMenu,
|
|
89
|
+
u as useSiteConfig,
|
|
90
|
+
hr as validateMenu,
|
|
91
|
+
dr as writeMenuDraft
|
|
92
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { writeMenuDraft as o, readMenuDraft as r } from "./menuDraftStorage.js";
|
|
2
|
+
function u(e) {
|
|
3
|
+
return new Promise((n, a) => {
|
|
4
|
+
const t = new FileReader();
|
|
5
|
+
t.onload = () => {
|
|
6
|
+
typeof t.result == "string" ? n(t.result) : a(new Error("Could not read image file."));
|
|
7
|
+
}, t.onerror = () => a(new Error("Could not read image file.")), t.readAsDataURL(e);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
const s = { authenticated: !0, strategy: "local", user: "local" };
|
|
11
|
+
function i(e, n) {
|
|
12
|
+
return {
|
|
13
|
+
getAdminSession: async () => s,
|
|
14
|
+
signInWithPassword: async () => s,
|
|
15
|
+
signOut: async () => {
|
|
16
|
+
},
|
|
17
|
+
getPublishedMenu: async () => r(n) ?? e,
|
|
18
|
+
getDraftMenu: async () => r(n) ?? e,
|
|
19
|
+
getDraft: async () => ({ menu: r(n) ?? e, etag: null }),
|
|
20
|
+
getAdminSignInUrl: () => "/admin",
|
|
21
|
+
saveDraftMenu: async (a) => (o(a, n), { etag: null }),
|
|
22
|
+
publishDraftMenu: async () => ({ ok: !0, backupKey: null }),
|
|
23
|
+
listMenuBackups: async () => [],
|
|
24
|
+
// Local dev has no publish history; "published" means the bundled seed.
|
|
25
|
+
restoreDraft: async () => (o(e, n), { etag: null }),
|
|
26
|
+
uploadMenuImage: async (a) => {
|
|
27
|
+
const t = await u(a);
|
|
28
|
+
return {
|
|
29
|
+
key: `local/images/${Date.now()}-${a.name}`,
|
|
30
|
+
url: t
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
deleteMenuImage: async () => {
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function c(e = "") {
|
|
38
|
+
return typeof window > "u" || e.trim() ? !1 : window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1";
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
i as createLocalMenuApiClient,
|
|
42
|
+
c as shouldUseLocalMenuApi
|
|
43
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
class d extends Error {
|
|
2
|
+
status;
|
|
3
|
+
constructor(t, n) {
|
|
4
|
+
super(t), this.name = "MenuApiError", this.status = n;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
function f(e = {}) {
|
|
8
|
+
const t = e.fetcher ?? fetch, n = e.apiBaseUrl ?? "", s = e.publicMenuUrl ?? p(n, "/api/menu");
|
|
9
|
+
return {
|
|
10
|
+
getPublishedMenu: () => o(t, s),
|
|
11
|
+
getDraftMenu: () => o(t, i(n, "/api/admin/menu/draft")),
|
|
12
|
+
getDraft: async () => {
|
|
13
|
+
const { body: a, response: r } = await c(t, i(n, "/api/admin/menu/draft"));
|
|
14
|
+
return { menu: a, etag: r.headers.get("etag") };
|
|
15
|
+
},
|
|
16
|
+
getAdminSignInUrl: (a) => {
|
|
17
|
+
const r = i(n, "/api/admin/sign-in");
|
|
18
|
+
return a ? `${r}?returnTo=${encodeURIComponent(a)}` : r;
|
|
19
|
+
},
|
|
20
|
+
getAdminSession: () => o(t, i(n, "/api/admin/session")),
|
|
21
|
+
signInWithPassword: async (a) => {
|
|
22
|
+
const r = await o(t, i(n, "/api/admin/login"), {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: {
|
|
25
|
+
"content-type": "application/json"
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({ password: a })
|
|
28
|
+
});
|
|
29
|
+
return { authenticated: !0, strategy: r.strategy, user: r.user };
|
|
30
|
+
},
|
|
31
|
+
signOut: async () => {
|
|
32
|
+
await o(t, i(n, "/api/admin/logout"), {
|
|
33
|
+
method: "POST"
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
saveDraftMenu: async (a, r = {}) => {
|
|
37
|
+
const { body: u, response: h } = await c(t, i(n, "/api/admin/menu/draft"), {
|
|
38
|
+
method: "PUT",
|
|
39
|
+
headers: {
|
|
40
|
+
"content-type": "application/json",
|
|
41
|
+
...r.ifMatch ? { "if-match": r.ifMatch } : {}
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify(a)
|
|
44
|
+
});
|
|
45
|
+
return { etag: u.etag ?? h.headers.get("etag") };
|
|
46
|
+
},
|
|
47
|
+
publishDraftMenu: () => o(t, i(n, "/api/admin/menu/publish"), {
|
|
48
|
+
method: "POST"
|
|
49
|
+
}),
|
|
50
|
+
listMenuBackups: async () => {
|
|
51
|
+
const { backups: a } = await o(t, i(n, "/api/admin/menu/backups"));
|
|
52
|
+
return a;
|
|
53
|
+
},
|
|
54
|
+
restoreDraft: async (a) => {
|
|
55
|
+
const { body: r } = await c(t, i(n, "/api/admin/menu/restore"), {
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: {
|
|
58
|
+
"content-type": "application/json"
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify(a.kind === "published" ? { source: "published" } : { source: "backup", key: a.key })
|
|
61
|
+
});
|
|
62
|
+
return { etag: r.etag ?? null };
|
|
63
|
+
},
|
|
64
|
+
uploadMenuImage: (a) => {
|
|
65
|
+
const r = new FormData();
|
|
66
|
+
return r.set("file", a), o(t, i(n, "/api/admin/images"), {
|
|
67
|
+
method: "POST",
|
|
68
|
+
body: r
|
|
69
|
+
}).then((u) => ({
|
|
70
|
+
...u,
|
|
71
|
+
url: m(u.url, n)
|
|
72
|
+
}));
|
|
73
|
+
},
|
|
74
|
+
deleteMenuImage: async (a) => {
|
|
75
|
+
await o(t, `${i(n, "/api/admin/images")}?key=${encodeURIComponent(a)}`, {
|
|
76
|
+
method: "DELETE"
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function i(e, t) {
|
|
82
|
+
return p(e, t);
|
|
83
|
+
}
|
|
84
|
+
function p(e, t) {
|
|
85
|
+
return e ? `${e.replace(/\/+$/, "")}/${t.replace(/^\/+/, "")}` : t;
|
|
86
|
+
}
|
|
87
|
+
function m(e, t) {
|
|
88
|
+
return !e || e.startsWith("http://") || e.startsWith("https://") ? e : p(t, e);
|
|
89
|
+
}
|
|
90
|
+
async function o(e, t, n) {
|
|
91
|
+
return (await c(e, t, n)).body;
|
|
92
|
+
}
|
|
93
|
+
async function c(e, t, n) {
|
|
94
|
+
let s;
|
|
95
|
+
try {
|
|
96
|
+
s = await e(t, {
|
|
97
|
+
credentials: "include",
|
|
98
|
+
...n
|
|
99
|
+
});
|
|
100
|
+
} catch {
|
|
101
|
+
throw new d("Could not reach the menu API. Check your connection, then retry.", 0);
|
|
102
|
+
}
|
|
103
|
+
const r = (s.headers.get("content-type") ?? "").includes("application/json");
|
|
104
|
+
if (!s.ok) {
|
|
105
|
+
const u = r ? g(await s.json()) : l(s);
|
|
106
|
+
throw new d(u, s.status);
|
|
107
|
+
}
|
|
108
|
+
if (!r)
|
|
109
|
+
throw new d("Expected a JSON response. The /api route is not reaching the menu Worker, or a sign-in page intercepted it.", s.status);
|
|
110
|
+
return { body: await s.json(), response: s };
|
|
111
|
+
}
|
|
112
|
+
function g(e) {
|
|
113
|
+
return e && typeof e == "object" && "error" in e && typeof e.error == "string" ? e.error : "Menu API request failed.";
|
|
114
|
+
}
|
|
115
|
+
function l(e) {
|
|
116
|
+
return e.status === 401 || e.status === 403 ? "You are not authorized to edit this menu." : e.status === 412 ? "The draft was changed elsewhere. Reload the editor to get the latest version." : e.status === 429 ? "Too many attempts. Wait a minute and try again." : `Menu API request failed with status ${e.status}.`;
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
d as MenuApiError,
|
|
120
|
+
f as createMenuApiClient
|
|
121
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
function n(t) {
|
|
2
|
+
return `${t}:menu-draft:v1`;
|
|
3
|
+
}
|
|
4
|
+
function r() {
|
|
5
|
+
return typeof window < "u" && typeof window.localStorage < "u";
|
|
6
|
+
}
|
|
7
|
+
function o(t) {
|
|
8
|
+
if (!r()) return null;
|
|
9
|
+
try {
|
|
10
|
+
const e = window.localStorage.getItem(t);
|
|
11
|
+
return e ? JSON.parse(e) : null;
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function a(t, e) {
|
|
17
|
+
if (r())
|
|
18
|
+
try {
|
|
19
|
+
window.localStorage.setItem(e, JSON.stringify(t));
|
|
20
|
+
} catch {
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function u(t) {
|
|
24
|
+
if (r())
|
|
25
|
+
try {
|
|
26
|
+
window.localStorage.removeItem(t);
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
u as clearMenuDraft,
|
|
32
|
+
n as menuDraftStorageKey,
|
|
33
|
+
o as readMenuDraft,
|
|
34
|
+
a as writeMenuDraft
|
|
35
|
+
};
|