PageSourceSearch

https://template-coral-five.vercel.app/assets/js/app.js?v=22

js template-coral-five.vercel.app collected 2026-10-03 07:51:14 UTC 4,676 bytes, 88 lines download raw bytes

1/* ----------------------------------------------------------------------------
2 *  app.js — boot the site
3 *
4 *  Flow: resolve the restaurant key -> load SIPO data -> build one clean
5 *  model -> apply the theme -> render. If the cache was stale, fresh data
6 *  arrives a moment later and the page seamlessly re-renders.
7 * -------------------------------------------------------------------------- */
8
9import { resolveOnlineKey, loadRestaurant } from "./api.js?v=22";
10import { buildModel } from "./state.js?v=22";
11import { applyTheme } from "./theme.js?v=22";
12import { renderSite } from "./render.js?v=22";
13
14// Build stamp — index.html's self-heal guard compares this to window.__BUILD__
15// to detect a stale cached module and force a one-time cache-busting reload.
16window.__APP_BUILD__ = "22";
17
18const ICONS = {
19  offline: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 1l22 22M16.7 16.7A6 6 0 0 0 12 15a6 6 0 0 0-4.7 1.7M5 12.5a10 10 0 0 1 3-2M19 12.5a10 10 0 0 0-5-2.6M2 8.8A16 16 0 0 1 8 5.6M22 8.8a16 16 0 0 0-6-3.2"/><circle cx="12" cy="20" r="1"/></svg>',
20  notfound: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3M8 11h6"/></svg>',
21  error: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"/><path d="M12 9v4M12 17h.01"/></svg>',
22  config: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.6 1.6 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.6 1.6 0 0 0-2.7 1.1V21a2 2 0 1 1-4 0v-.1A1.6 1.6 0 0 0 7 19.4a1.6 1.6 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1A1.6 1.6 0 0 0 3 14a2 2 0 1 1 0-4 1.6 1.6 0 0 0 1.5-2.6 2 2 0 1 1 2.8-2.8 1.6 1.6 0 0 0 2.7-1.1V3a2 2 0 1 1 4 0 1.6 1.6 0 0 0 2.6 1.5 2 2 0 1 1 2.8 2.8A1.6 1.6 0 0 0 21 10a2 2 0 1 1 0 4Z"/></svg>'
23};
24const COPY = {
25  offline:  ["You're offline", "We can't reach the internet right now. Check your connection and try again."],
26  notfound: ["Restaurant not found", "We couldn't find a restaurant for this key. Please verify it and try again."],
27  config:   ["Not configured yet", "No restaurant key is set. Open config.js and set ONLINE_KEY."],
28  error:    ["Something went wrong", "We hit an unexpected problem loading this restaurant. Please try again."]
29};
30
31function fatal(type, detail) {
32  const [title, msg] = COPY[type] || COPY.error;
33  document.getElementById("fatal-icon").innerHTML = ICONS[type] || ICONS.error;
34  document.getElementById("fatal-title").textContent = title;
35  document.getElementById("fatal-msg").textContent = detail || msg;
36  document.getElementById("boot").style.display = "none";
37  document.getElementById("fatal").hidden = false;
38}
39
40function paint(payload) {
41  const model = buildModel(payload);
42  applyTheme(model);
43  renderSite(model);
44  // Smooth-scroll for in-page anchors (non-critical — never let it fail paint).
45  try {
46    document.querySelectorAll('a[href^="#"]').forEach((a) =>
47      a.addEventListener("click", (e) => {
48        const id = a.getAttribute("href").slice(1);
49        const t = id && document.getElementById(id);
50        if (t) { e.preventDefault(); t.scrollIntoView({ behavior: "smooth", block: "start" });
51          document.getElementById("mnav") && document.getElementById("mnav").classList.remove("open"); }
52      }));
53  } catch (e) { console.error("[anchors]", e); }
54  return model;
55}
56
57function classify(err) {
58  if (typeof navigator !== "undefined" && navigator.onLine === false) return "offline";
59  const m = (err && err.message) || "";
60  if (err && err.name === "TypeError") return "offline";          // fetch failed
61  if (/invalid restaurant key|no data/i.test(m)) return "notfound";
62  return "error";
63}
64
65async function boot() {
66  const key = resolveOnlineKey();
67  if (!key) return fatal("config");
68
69  try {
70    const data = await loadRestaurant(key, (fresh) => {
71      try { paint(fresh); } catch (e) { console.error(e); }
72    });
73    paint(data);
74  } catch (err) {
75    console.error(err);
76    // Also surface on the visible diagnostic bar (handled errors don't
77    // fire window.onerror), so the real cause is always on screen.
78    if (window.__diag) window.__diag("Load error", (err && (err.stack || err.message)) || String(err));
79    fatal(classify(err), err && err.message ? "Details: " + err.message : null);
80  }
81}
82
83// If the connection drops while browsing, let the user know on next action.
84window.addEventListener("offline", () => {
85  if (!document.body.classList.contains("ready")) fatal("offline");
86});
87
88boot();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.