@agent-cms/agentcms 0.0.0-stage → 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 +143 -0
- package/README.md +1119 -2
- package/changelog.json +20 -0
- package/dist/admin/admin-files.json +48 -0
- package/dist/admin/assets/CodeEditor-DcFzGUt8.js +24 -0
- package/dist/admin/assets/flexweg-logo-CdtuqAFA.png +0 -0
- package/dist/admin/assets/index-CLZ1gQZl.js +5460 -0
- package/dist/admin/assets/index-DMcGogR2.css +1 -0
- package/dist/admin/assets/sql-wasm-C1U8OeUW.wasm +0 -0
- package/dist/admin/assets/sql-wasm-CYl3LXH_.js +2 -0
- package/dist/admin/assets/sql-wasm-V5jTDcrT.js +1 -0
- package/dist/admin/config.js +11 -0
- package/dist/admin/external.default.json +72 -0
- package/dist/admin/index.html +116 -0
- package/dist/admin/plugins/core-seo/bundle.js +55 -0
- package/dist/admin/plugins/core-seo/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-archives/bundle.js +1414 -0
- package/dist/admin/plugins/flexweg-archives/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-multilang/bundle.js +1187 -0
- package/dist/admin/plugins/flexweg-multilang/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-rss/bundle.js +1354 -0
- package/dist/admin/plugins/flexweg-rss/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-search/bundle.js +1243 -0
- package/dist/admin/plugins/flexweg-search/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-sitemaps/bundle.js +1293 -0
- package/dist/admin/plugins/flexweg-sitemaps/manifest.json +7 -0
- package/dist/admin/runtime/cms-runtime.js +164 -0
- package/dist/admin/runtime/react-dom-client.js +13 -0
- package/dist/admin/runtime/react-dom.js +16 -0
- package/dist/admin/runtime/react-i18next.js +21 -0
- package/dist/admin/runtime/react-jsx-runtime.js +17 -0
- package/dist/admin/runtime/react.js +55 -0
- package/dist/admin/themes/corporate/bundle.js +14465 -0
- package/dist/admin/themes/corporate/manifest.json +7 -0
- package/dist/admin/themes/corporate/theme.css +2 -0
- package/dist/admin/themes/magazine/bundle.js +10229 -0
- package/dist/admin/themes/magazine/manifest.json +7 -0
- package/dist/admin/themes/magazine/theme.css +2 -0
- package/dist/admin/themes/marketplace-core/bundle.js +11213 -0
- package/dist/admin/themes/marketplace-core/manifest.json +7 -0
- package/dist/admin/themes/marketplace-core/theme.css +1613 -0
- package/dist/admin/themes/portfolio/bundle.js +9195 -0
- package/dist/admin/themes/portfolio/manifest.json +7 -0
- package/dist/admin/themes/portfolio/theme.css +2 -0
- package/dist/admin/themes/storefront/bundle.js +13172 -0
- package/dist/admin/themes/storefront/manifest.json +7 -0
- package/dist/admin/themes/storefront/theme.css +2 -0
- package/dist/agent/agentcms.mjs +1711 -0
- package/dist/agent/chunks/hosting-D_uj-Mt1.mjs +117 -0
- package/dist/agent/chunks/index-CrvEoyi0.mjs +3608 -0
- package/dist/agent/chunks/install-DkCCcKAO.mjs +577 -0
- package/dist/agent/chunks/plan-EYKegfhp.mjs +245 -0
- package/dist/agent/chunks/registry-lkfb_E9O.mjs +53517 -0
- package/dist/agent/chunks/siteAdd-BqcYt8nu.mjs +118 -0
- package/dist/agent/chunks/sql-wasm-GjJDiefO.mjs +10 -0
- package/dist/agent/chunks/sqljs-DjSCStJ0.mjs +20 -0
- package/dist/agent/vendor/sql-wasm.cjs +188 -0
- package/dist/theme-assets/corporate-menu.js +266 -0
- package/dist/theme-assets/corporate-posts.js +571 -0
- package/dist/theme-assets/corporate.css +2 -0
- package/dist/theme-assets/default-menu.js +266 -0
- package/dist/theme-assets/default-posts.js +378 -0
- package/dist/theme-assets/default.css +1 -0
- package/dist/theme-assets/magazine-menu.js +227 -0
- package/dist/theme-assets/magazine-posts.js +361 -0
- package/dist/theme-assets/magazine.css +2 -0
- package/dist/theme-assets/portfolio-filters.js +104 -0
- package/dist/theme-assets/portfolio-menu.js +240 -0
- package/dist/theme-assets/portfolio-posts.js +358 -0
- package/dist/theme-assets/portfolio.css +2 -0
- package/dist/theme-assets/storefront-catalog.js +504 -0
- package/dist/theme-assets/storefront-menu.js +239 -0
- package/dist/theme-assets/storefront-posts.js +404 -0
- package/dist/theme-assets/storefront.css +2 -0
- package/dist/version.json +9 -0
- package/package.json +101 -4
- package/plugin/.claude-plugin/plugin.json +16 -0
- package/plugin/skills/agentcms-install/SKILL.md +110 -0
- package/plugin/skills/agentcms-install/references/cloudflare.md +15 -0
- package/plugin/skills/agentcms-install/references/flexweg.md +11 -0
- package/plugin/skills/agentcms-install/references/github.md +67 -0
- package/plugin/skills/agentcms-install/references/gitlab.md +15 -0
- package/plugin/skills/agentcms-install/references/s3.md +81 -0
- package/plugin/skills/agentcms-manage/SKILL.md +92 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portfolio theme — runtime project filters.
|
|
3
|
+
*
|
|
4
|
+
* Wires the [data-cms-portfolio-filters] chip cloud on the home page
|
|
5
|
+
* (and any other page that ships filterable cards). Source of truth
|
|
6
|
+
* is the rendered DOM:
|
|
7
|
+
* - Every project card carries `data-cms-category="<slug>"`.
|
|
8
|
+
* - The chip cloud already has an "All" chip with
|
|
9
|
+
* `data-cms-filter="*"` baked in by the template.
|
|
10
|
+
*
|
|
11
|
+
* On boot we:
|
|
12
|
+
* 1. Read every unique category slug present on the page.
|
|
13
|
+
* 2. Append one button[data-cms-filter="<slug>"] per slug to the
|
|
14
|
+
* filter host, labelled from the first card carrying that slug
|
|
15
|
+
* via its category meta (the meta is uppercase already).
|
|
16
|
+
* 3. Wire click handlers that toggle `is-active` on the buttons
|
|
17
|
+
* and show/hide cards (display:none) by matching
|
|
18
|
+
* `data-cms-category`.
|
|
19
|
+
*
|
|
20
|
+
* The implementation is purposefully without animation — the design
|
|
21
|
+
* system rejects transitions on layout to keep the architectural
|
|
22
|
+
* feel. The card list reflows instantly.
|
|
23
|
+
*/
|
|
24
|
+
(function () {
|
|
25
|
+
"use strict";
|
|
26
|
+
|
|
27
|
+
function init() {
|
|
28
|
+
var host = document.querySelector("[data-cms-portfolio-filters]");
|
|
29
|
+
if (!host) return;
|
|
30
|
+
var cards = Array.prototype.slice.call(
|
|
31
|
+
document.querySelectorAll("[data-cms-category]"),
|
|
32
|
+
);
|
|
33
|
+
if (cards.length === 0) {
|
|
34
|
+
host.setAttribute("hidden", "");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Gather unique slugs + their human label (taken from the
|
|
39
|
+
// first card's `.project-card__meta` text — the "CATEGORY / 2024"
|
|
40
|
+
// string. We split on " / " and use the leading word.)
|
|
41
|
+
var slugToLabel = {};
|
|
42
|
+
cards.forEach(function (card) {
|
|
43
|
+
var slug = card.getAttribute("data-cms-category");
|
|
44
|
+
if (!slug) return;
|
|
45
|
+
if (slugToLabel[slug]) return;
|
|
46
|
+
var metaEl = card.querySelector(".project-card__meta");
|
|
47
|
+
var rawMeta = metaEl ? metaEl.textContent || "" : "";
|
|
48
|
+
var label = rawMeta.split(" / ")[0].trim();
|
|
49
|
+
slugToLabel[slug] = label || slug.toUpperCase();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
var slugs = Object.keys(slugToLabel).sort();
|
|
53
|
+
if (slugs.length === 0) {
|
|
54
|
+
host.setAttribute("hidden", "");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Append a chip button per slug. The "All" chip (data-cms-filter="*")
|
|
59
|
+
// is already in the DOM from the template.
|
|
60
|
+
slugs.forEach(function (slug) {
|
|
61
|
+
var chip = document.createElement("button");
|
|
62
|
+
chip.type = "button";
|
|
63
|
+
chip.className = "portfolio-btn-outline";
|
|
64
|
+
chip.setAttribute("data-cms-filter", slug);
|
|
65
|
+
chip.textContent = slugToLabel[slug];
|
|
66
|
+
host.appendChild(chip);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
function applyFilter(slug) {
|
|
70
|
+
var showAll = slug === "*" || !slug;
|
|
71
|
+
cards.forEach(function (card) {
|
|
72
|
+
if (showAll) {
|
|
73
|
+
card.style.display = "";
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
var cardSlug = card.getAttribute("data-cms-category");
|
|
77
|
+
card.style.display = cardSlug === slug ? "" : "none";
|
|
78
|
+
});
|
|
79
|
+
// Update active state on the chips.
|
|
80
|
+
host.querySelectorAll("[data-cms-filter]").forEach(function (btn) {
|
|
81
|
+
var thisSlug = btn.getAttribute("data-cms-filter");
|
|
82
|
+
if (thisSlug === slug || (showAll && thisSlug === "*")) {
|
|
83
|
+
btn.classList.add("is-active");
|
|
84
|
+
} else {
|
|
85
|
+
btn.classList.remove("is-active");
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
host.addEventListener("click", function (event) {
|
|
91
|
+
var target = event.target;
|
|
92
|
+
if (!(target instanceof Element)) return;
|
|
93
|
+
var btn = target.closest("[data-cms-filter]");
|
|
94
|
+
if (!btn) return;
|
|
95
|
+
applyFilter(btn.getAttribute("data-cms-filter"));
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (document.readyState === "loading") {
|
|
100
|
+
document.addEventListener("DOMContentLoaded", init);
|
|
101
|
+
} else {
|
|
102
|
+
init();
|
|
103
|
+
}
|
|
104
|
+
})();
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storefront theme — runtime menu loader.
|
|
3
|
+
*
|
|
4
|
+
* Same contract as default / magazine / corporate: fetches /data/menu.json
|
|
5
|
+
* and paints every `[data-cms-menu]` container on the page. The storefront
|
|
6
|
+
* header ships TWO such containers — the inline horizontal nav (visible
|
|
7
|
+
* md+) and the off-canvas burger overlay (always present, opens on
|
|
8
|
+
* burger-toggle click). The storefront bottom-nav links also pick up the
|
|
9
|
+
* `aria-current="page"` state via the same `samePath` helper.
|
|
10
|
+
*
|
|
11
|
+
* Differences vs corporate:
|
|
12
|
+
* - Branding logo gets `h-8 w-auto` to fit the storefront header (h-16).
|
|
13
|
+
* - Burger menu links use the editorial serif + sage active color.
|
|
14
|
+
*/
|
|
15
|
+
(function () {
|
|
16
|
+
"use strict";
|
|
17
|
+
|
|
18
|
+
// ─── Base path ────────────────────────────────────────────────────
|
|
19
|
+
// Sites served from a sub-folder (e.g. GitHub Pages project sites)
|
|
20
|
+
// carry <meta name="x-cms-base" content="/repo/"> in <head>; no meta
|
|
21
|
+
// means the site lives at the domain root. URLs built at runtime from
|
|
22
|
+
// JSON data go through withBase() so they land under that folder.
|
|
23
|
+
var BASE = (function () {
|
|
24
|
+
var meta = document.querySelector('meta[name="x-cms-base"]');
|
|
25
|
+
var b = (meta && meta.getAttribute("content")) || "/";
|
|
26
|
+
if (b.charAt(0) !== "/") b = "/" + b;
|
|
27
|
+
if (b.charAt(b.length - 1) !== "/") b += "/";
|
|
28
|
+
return b;
|
|
29
|
+
})();
|
|
30
|
+
|
|
31
|
+
function withBase(url) {
|
|
32
|
+
if (BASE === "/" || !url) return url;
|
|
33
|
+
// Absolute URLs (http:, mailto:, data:, …), protocol-relative and
|
|
34
|
+
// fragment-only links pass through.
|
|
35
|
+
if (/^([a-z][a-z0-9+.-]*:|\/\/|#)/i.test(url)) return url;
|
|
36
|
+
if (url.indexOf(BASE) === 0 || url === BASE.slice(0, -1)) return url;
|
|
37
|
+
return BASE + (url.charAt(0) === "/" ? url.slice(1) : url);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function fetchMenu() {
|
|
41
|
+
return fetch(withBase("/data/menu.json"), { credentials: "omit" })
|
|
42
|
+
.then(function (res) {
|
|
43
|
+
if (!res.ok) throw new Error("HTTP " + res.status);
|
|
44
|
+
return res.json();
|
|
45
|
+
})
|
|
46
|
+
.catch(function (err) {
|
|
47
|
+
console.warn("[cms] menu.json load failed:", err);
|
|
48
|
+
return null;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function samePath(href) {
|
|
53
|
+
try {
|
|
54
|
+
var url = new URL(href, window.location.origin);
|
|
55
|
+
var here = window.location.pathname.replace(/\/index\.html$/, "/");
|
|
56
|
+
var there = url.pathname.replace(/\/index\.html$/, "/");
|
|
57
|
+
return here === there;
|
|
58
|
+
} catch (e) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Picks the per-language label from item.labels (set by the admin
|
|
64
|
+
// in the menu builder) based on <html lang>, with a region-stripped
|
|
65
|
+
// fallback so "en-US" matches "en". Mono-lingual sites just return
|
|
66
|
+
// item.label.
|
|
67
|
+
function pickLabel(item) {
|
|
68
|
+
var lang = (document.documentElement.getAttribute("lang") || "").trim();
|
|
69
|
+
if (lang && item.labels && typeof item.labels[lang] === "string" && item.labels[lang]) {
|
|
70
|
+
return item.labels[lang];
|
|
71
|
+
}
|
|
72
|
+
if (lang && lang.indexOf("-") > 0) {
|
|
73
|
+
var base = lang.split("-")[0];
|
|
74
|
+
if (item.labels && typeof item.labels[base] === "string" && item.labels[base]) {
|
|
75
|
+
return item.labels[base];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return item.label || "";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function renderBurgerItem(item) {
|
|
82
|
+
var li = document.createElement("li");
|
|
83
|
+
var a = document.createElement("a");
|
|
84
|
+
a.href = withBase(item.href) || "#";
|
|
85
|
+
a.textContent = pickLabel(item);
|
|
86
|
+
if (samePath(a.href)) a.setAttribute("aria-current", "page");
|
|
87
|
+
li.appendChild(a);
|
|
88
|
+
if (item.children && item.children.length) {
|
|
89
|
+
var sub = document.createElement("ul");
|
|
90
|
+
sub.className = "menu-children";
|
|
91
|
+
item.children.forEach(function (child) {
|
|
92
|
+
sub.appendChild(renderBurgerItem(child));
|
|
93
|
+
});
|
|
94
|
+
li.appendChild(sub);
|
|
95
|
+
}
|
|
96
|
+
return li;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function renderInlineItem(item) {
|
|
100
|
+
var a = document.createElement("a");
|
|
101
|
+
a.href = withBase(item.href) || "#";
|
|
102
|
+
a.textContent = pickLabel(item);
|
|
103
|
+
// Portfolio nav uses the `nav-link` component class declared in
|
|
104
|
+
// theme.css — the active-state pink dot lives there. No
|
|
105
|
+
// Tailwind-specific styling per link here so the theme can change
|
|
106
|
+
// typography without rebuilding the loader.
|
|
107
|
+
a.className = "nav-link";
|
|
108
|
+
var active = samePath(a.href);
|
|
109
|
+
if (active) {
|
|
110
|
+
a.setAttribute("aria-current", "page");
|
|
111
|
+
a.classList.add("is-active");
|
|
112
|
+
}
|
|
113
|
+
return a;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function paint(menu) {
|
|
117
|
+
if (!menu) return;
|
|
118
|
+
document.querySelectorAll("[data-cms-menu]").forEach(function (host) {
|
|
119
|
+
var key = host.getAttribute("data-cms-menu");
|
|
120
|
+
var items = (menu && menu[key]) || [];
|
|
121
|
+
var inline = host.hasAttribute("data-cms-menu-inline");
|
|
122
|
+
|
|
123
|
+
if (inline) {
|
|
124
|
+
host.innerHTML = "";
|
|
125
|
+
items.forEach(function (item) {
|
|
126
|
+
host.appendChild(renderInlineItem(item));
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
var list = host.querySelector("ul");
|
|
130
|
+
if (!list) return;
|
|
131
|
+
list.innerHTML = "";
|
|
132
|
+
items.forEach(function (item) {
|
|
133
|
+
list.appendChild(renderBurgerItem(item));
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Hide empty inline / footer hosts so they don't reserve
|
|
138
|
+
// whitespace. Skip #burger-menu: it's `position: fixed` (no
|
|
139
|
+
// layout impact) AND any `hidden` attribute would `display:
|
|
140
|
+
// none` the panel, which the `.burger-menu.is-open { transform:
|
|
141
|
+
// translate(0) }` rule can never override — the burger toggle
|
|
142
|
+
// would open an invisible panel. Visibility of the burger UI is
|
|
143
|
+
// gated by the burger TOGGLE button below instead.
|
|
144
|
+
var isBurgerMenu = host.id === "burger-menu";
|
|
145
|
+
if (items.length === 0 && !isBurgerMenu) host.setAttribute("hidden", "");
|
|
146
|
+
else host.removeAttribute("hidden");
|
|
147
|
+
});
|
|
148
|
+
// Hide the burger TOGGLE button when the header menu has no
|
|
149
|
+
// items — otherwise users see a button that opens an empty
|
|
150
|
+
// off-canvas panel and conclude "the burger is broken".
|
|
151
|
+
var headerItems = (menu && menu.header) || [];
|
|
152
|
+
document.querySelectorAll(".burger-toggle").forEach(function (toggle) {
|
|
153
|
+
if (headerItems.length === 0) toggle.setAttribute("hidden", "");
|
|
154
|
+
else toggle.removeAttribute("hidden");
|
|
155
|
+
});
|
|
156
|
+
paintBranding(menu);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Swap the wordmark for an <img> when the theme has a logo
|
|
160
|
+
// configured. Falls back to the static text in every other case.
|
|
161
|
+
function paintBranding(menu) {
|
|
162
|
+
var branding = menu && menu.branding;
|
|
163
|
+
var logoUrl = branding && branding.logoUrl;
|
|
164
|
+
if (!logoUrl) return;
|
|
165
|
+
document.querySelectorAll("[data-cms-brand]").forEach(function (host) {
|
|
166
|
+
var alt = host.textContent || "";
|
|
167
|
+
var img = document.createElement("img");
|
|
168
|
+
img.src = withBase(logoUrl);
|
|
169
|
+
img.alt = alt;
|
|
170
|
+
img.className = "h-8 w-auto";
|
|
171
|
+
img.loading = "lazy";
|
|
172
|
+
host.innerHTML = "";
|
|
173
|
+
host.appendChild(img);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function ensureCloseButton(menu) {
|
|
178
|
+
if (menu.querySelector(".burger-close")) return menu.querySelector(".burger-close");
|
|
179
|
+
var close = document.createElement("button");
|
|
180
|
+
close.type = "button";
|
|
181
|
+
close.className = "burger-close";
|
|
182
|
+
close.setAttribute("aria-label", "Close menu");
|
|
183
|
+
close.innerHTML =
|
|
184
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
|
|
185
|
+
menu.insertBefore(close, menu.firstChild);
|
|
186
|
+
return close;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function ensureBackdrop() {
|
|
190
|
+
var existing = document.querySelector(".burger-backdrop");
|
|
191
|
+
if (existing) return existing;
|
|
192
|
+
var backdrop = document.createElement("div");
|
|
193
|
+
backdrop.className = "burger-backdrop";
|
|
194
|
+
backdrop.setAttribute("aria-hidden", "true");
|
|
195
|
+
document.body.appendChild(backdrop);
|
|
196
|
+
return backdrop;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function wireBurger() {
|
|
200
|
+
var toggle = document.querySelector(".burger-toggle");
|
|
201
|
+
var menu = document.getElementById("burger-menu");
|
|
202
|
+
if (!toggle || !menu) return;
|
|
203
|
+
var close = ensureCloseButton(menu);
|
|
204
|
+
var backdrop = ensureBackdrop();
|
|
205
|
+
function setOpen(open) {
|
|
206
|
+
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
|
207
|
+
menu.classList.toggle("is-open", open);
|
|
208
|
+
backdrop.classList.toggle("is-open", open);
|
|
209
|
+
document.body.classList.toggle("burger-open", open);
|
|
210
|
+
}
|
|
211
|
+
toggle.addEventListener("click", function () {
|
|
212
|
+
var isOpen = toggle.getAttribute("aria-expanded") === "true";
|
|
213
|
+
setOpen(!isOpen);
|
|
214
|
+
});
|
|
215
|
+
close.addEventListener("click", function () { setOpen(false); });
|
|
216
|
+
backdrop.addEventListener("click", function () { setOpen(false); });
|
|
217
|
+
document.addEventListener("keydown", function (e) {
|
|
218
|
+
if (e.key === "Escape") setOpen(false);
|
|
219
|
+
});
|
|
220
|
+
menu.addEventListener("click", function (e) {
|
|
221
|
+
if (e.target.tagName === "A") setOpen(false);
|
|
222
|
+
});
|
|
223
|
+
document.addEventListener("pointerdown", function (e) {
|
|
224
|
+
if (toggle.getAttribute("aria-expanded") !== "true") return;
|
|
225
|
+
if (menu.contains(e.target)) return;
|
|
226
|
+
if (toggle.contains(e.target)) return;
|
|
227
|
+
setOpen(false);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function ready(fn) {
|
|
232
|
+
if (document.readyState !== "loading") fn();
|
|
233
|
+
else document.addEventListener("DOMContentLoaded", fn);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
ready(function () {
|
|
237
|
+
wireBurger();
|
|
238
|
+
fetchMenu().then(paint);
|
|
239
|
+
});
|
|
240
|
+
})();
|