@bagelink/blox 1.15.176 → 1.15.180

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.
Files changed (67) hide show
  1. package/dist/{PreviewApp-B8EmNfyH.cjs → PreviewApp-APyemzqx.cjs} +1 -1
  2. package/dist/{PreviewApp-DdkAQqw2.js → PreviewApp-BKTydm92.js} +1 -1
  3. package/dist/{PreviewApp.vue_vue_type_style_index_0_lang-CPBuld3j.cjs → PreviewApp.vue_vue_type_style_index_0_lang-C0ZVst7R.cjs} +6 -6
  4. package/dist/{PreviewApp.vue_vue_type_style_index_0_lang-1JKQVLm2.js → PreviewApp.vue_vue_type_style_index_0_lang-DHb-NJ4C.js} +1 -1
  5. package/dist/api/index.d.ts +22 -0
  6. package/dist/api/index.d.ts.map +1 -1
  7. package/dist/components/BloxRouterView.vue.d.ts +26 -15
  8. package/dist/components/BloxRouterView.vue.d.ts.map +1 -1
  9. package/dist/composables/useLocale.d.ts +7 -0
  10. package/dist/composables/useLocale.d.ts.map +1 -1
  11. package/dist/composables/useLocaleNav.d.ts +2 -2
  12. package/dist/composables/useLocaleNav.d.ts.map +1 -1
  13. package/dist/content/{ContentDetailHost.vue.d.ts → ContentDetailView.vue.d.ts} +1 -1
  14. package/dist/content/ContentDetailView.vue.d.ts.map +1 -0
  15. package/dist/content/ContentHost.vue.d.ts +3 -0
  16. package/dist/content/ContentHost.vue.d.ts.map +1 -0
  17. package/dist/content/index.d.ts +9 -0
  18. package/dist/content/index.d.ts.map +1 -0
  19. package/dist/content/registry.d.ts +73 -0
  20. package/dist/content/registry.d.ts.map +1 -0
  21. package/dist/content/routes.d.ts +48 -0
  22. package/dist/content/routes.d.ts.map +1 -0
  23. package/dist/content/useContentItem.d.ts +37 -5
  24. package/dist/content/useContentItem.d.ts.map +1 -1
  25. package/dist/content/useContentSeo.d.ts +20 -7
  26. package/dist/content/useContentSeo.d.ts.map +1 -1
  27. package/dist/core.d.ts +3 -1
  28. package/dist/core.d.ts.map +1 -1
  29. package/dist/createBloxApp.d.ts.map +1 -1
  30. package/dist/data/useData.d.ts +91 -0
  31. package/dist/data/useData.d.ts.map +1 -0
  32. package/dist/index.cjs +185 -138
  33. package/dist/index.d.ts +7 -13
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.mjs +177 -131
  36. package/dist/localeRoutes.d.ts +15 -0
  37. package/dist/localeRoutes.d.ts.map +1 -0
  38. package/dist/localeStrategy.d.ts +13 -0
  39. package/dist/localeStrategy.d.ts.map +1 -1
  40. package/dist/{prerender-NHAqrTm3.js → prerender-DB1R4jiQ.js} +10 -9
  41. package/dist/{prerender-H72-UrK4.cjs → prerender-DXGy7pee.cjs} +10 -9
  42. package/dist/{core-KRHc4Bob.cjs → routes-C97aL4cQ.cjs} +415 -220
  43. package/dist/{core-Bp2bf8e4.js → routes-bhjTTXfU.js} +444 -249
  44. package/dist/ssg/cli.cjs +1 -1
  45. package/dist/ssg/cli.mjs +1 -1
  46. package/dist/ssg/createSSREntry.d.ts.map +1 -1
  47. package/dist/ssg/index.cjs +28 -19
  48. package/dist/ssg/index.mjs +31 -22
  49. package/dist/ssg/render-resolved-page.d.ts +6 -0
  50. package/dist/ssg/render-resolved-page.d.ts.map +1 -1
  51. package/dist/ssg/seo.d.ts +9 -3
  52. package/dist/ssg/seo.d.ts.map +1 -1
  53. package/dist/vite-plugin.cjs +2 -2
  54. package/dist/vite-plugin.d.ts.map +1 -1
  55. package/dist/vite-plugin.mjs +2 -2
  56. package/package.json +1 -1
  57. package/dist/components/LocaleRouterLink.vue.d.ts +0 -28
  58. package/dist/components/LocaleRouterLink.vue.d.ts.map +0 -1
  59. package/dist/composables/useData.d.ts +0 -22
  60. package/dist/composables/useData.d.ts.map +0 -1
  61. package/dist/composables/useSeo.d.ts +0 -20
  62. package/dist/composables/useSeo.d.ts.map +0 -1
  63. package/dist/content/ContentDetailHost.vue.d.ts.map +0 -1
  64. package/dist/content/defineContent.d.ts +0 -22
  65. package/dist/content/defineContent.d.ts.map +0 -1
  66. package/dist/routing/withLocaleRoutes.d.ts +0 -8
  67. package/dist/routing/withLocaleRoutes.d.ts.map +0 -1
@@ -2,21 +2,32 @@
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
- const ssg_client = require("./ssg/client.cjs");
6
5
  const vue = require("vue");
7
6
  const vueRouter = require("vue-router");
7
+ const ssg_client = require("./ssg/client.cjs");
8
8
  const vue$1 = require("@bagelink/vue");
9
- const BASE = "/api";
9
+ let BASE = "/api";
10
10
  let _websiteName = "";
11
11
  let _store = "";
12
12
  let _websiteId = null;
13
+ let _origin = "";
13
14
  function configureApi(websiteName, store) {
14
15
  _websiteName = websiteName;
15
16
  _store = store;
16
17
  _websiteId = null;
17
18
  }
19
+ function setApiOrigin(base) {
20
+ if (!base) return;
21
+ try {
22
+ const u = new URL(base);
23
+ _origin = u.origin;
24
+ BASE = u.pathname && u.pathname !== "/" ? u.pathname.replace(/\/$/, "") : "";
25
+ } catch {
26
+ }
27
+ }
18
28
  async function request(path, { locale: locale2, params, ...opts } = {}) {
19
- const url = new URL(`${BASE}${path}`, window.location.origin);
29
+ const origin = _origin || (typeof window !== "undefined" ? window.location.origin : "");
30
+ const url = new URL(`${BASE}${path}`, origin || void 0);
20
31
  if (locale2) url.searchParams.set("locale", locale2);
21
32
  if (params) {
22
33
  for (const [k, v] of Object.entries(params)) url.searchParams.set(k, String(v));
@@ -62,6 +73,16 @@ async function listItems(collection, { locale: locale2, q, offset = 0, limit = 1
62
73
  params: { ...q ? { q } : {}, offset, limit }
63
74
  });
64
75
  }
76
+ async function getItemBySlug(collection, slug, locale2) {
77
+ const res = await listItems(collection, { locale: locale2, q: `slug eq "${slug}"`, limit: 1 });
78
+ const items = Array.isArray(res) ? res : (res == null ? void 0 : res.items) ?? [];
79
+ return items[0] ?? null;
80
+ }
81
+ async function getItemById(collection, id, locale2) {
82
+ const res = await listItems(collection, { locale: locale2, q: `id eq "${id}"`, limit: 1 });
83
+ const items = Array.isArray(res) ? res : (res == null ? void 0 : res.items) ?? [];
84
+ return items[0] ?? null;
85
+ }
65
86
  const BLOX_REGISTRY_KEY = Symbol("blox:registry");
66
87
  const BLOX_CONFIG_KEY = Symbol("blox:config");
67
88
  const BLOX_LOCALE_STRATEGY_KEY = Symbol("blox:locale-strategy");
@@ -116,7 +137,7 @@ function useBloxEdit(configOverride) {
116
137
  }
117
138
  return { config, enabled, showEdit, studioBaseUrl, editUrl, enable, dismiss, init };
118
139
  }
119
- const _hoisted_1$3 = {
140
+ const _hoisted_1$2 = {
120
141
  key: 0,
121
142
  class: "blox-admin-bar"
122
143
  };
@@ -139,7 +160,7 @@ const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
139
160
  key: 0,
140
161
  to: "body"
141
162
  }, [
142
- vue.unref(showEdit) && __props.websiteId && __props.pageId ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
163
+ vue.unref(showEdit) && __props.websiteId && __props.pageId ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
143
164
  vue.createElementVNode("button", {
144
165
  type: "button",
145
166
  class: "blox-admin-btn",
@@ -160,15 +181,26 @@ const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
160
181
  };
161
182
  }
162
183
  });
163
- const locale = vue.ref(localStorage.getItem("blox:locale") || "en");
184
+ const _hasStorage = typeof localStorage !== "undefined";
185
+ const locale = vue.ref((_hasStorage ? localStorage.getItem("blox:locale") : null) || "en");
164
186
  const currentAlternates = vue.ref({});
187
+ function setActiveLocale(l) {
188
+ locale.value = l;
189
+ try {
190
+ const i18n = vue$1.getI18n();
191
+ if (i18n == null ? void 0 : i18n.global) i18n.global.locale.value = l;
192
+ } catch {
193
+ }
194
+ }
165
195
  function useLocale() {
166
196
  const dir = vue.computed(() => locale.value === "he" || locale.value === "ar" ? "rtl" : "ltr");
167
197
  function setLocale(l) {
168
198
  locale.value = l;
169
- localStorage.setItem("blox:locale", l);
170
- document.documentElement.lang = l;
171
- document.documentElement.dir = dir.value;
199
+ if (typeof localStorage !== "undefined") localStorage.setItem("blox:locale", l);
200
+ if (typeof document !== "undefined") {
201
+ document.documentElement.lang = l;
202
+ document.documentElement.dir = dir.value;
203
+ }
172
204
  try {
173
205
  const i18n = vue$1.getI18n();
174
206
  if (i18n == null ? void 0 : i18n.global) i18n.global.locale.value = l;
@@ -284,7 +316,7 @@ const PageRenderer = vue.defineComponent({
284
316
  );
285
317
  }
286
318
  });
287
- const _hoisted_1$2 = {
319
+ const _hoisted_1$1 = {
288
320
  key: 0,
289
321
  class: "blox-loading flex column h-100vh justify-content-center"
290
322
  };
@@ -292,11 +324,11 @@ const _hoisted_2$1 = {
292
324
  key: 1,
293
325
  class: "blox-not-found"
294
326
  };
295
- const _hoisted_3 = {
327
+ const _hoisted_3$1 = {
296
328
  key: 2,
297
329
  class: "blox-error color-red"
298
330
  };
299
- const _hoisted_4 = {
331
+ const _hoisted_4$1 = {
300
332
  key: 0,
301
333
  class: "blox-nav-progress"
302
334
  };
@@ -400,7 +432,7 @@ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
400
432
  return (_ctx, _cache) => {
401
433
  const _component_RouterLink = vue.resolveComponent("RouterLink");
402
434
  return vue.openBlock(), vue.createElementBlock("div", null, [
403
- initialLoading.value && blocks.value.length === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
435
+ initialLoading.value && blocks.value.length === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
404
436
  vue.createVNode(vue.unref(vue$1.Loading))
405
437
  ])) : notFound.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$1, [
406
438
  _cache[0] || (_cache[0] = vue.createElementVNode("h2", null, "404", -1)),
@@ -411,8 +443,8 @@ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
411
443
  ]),
412
444
  _: 1
413
445
  })
414
- ])) : error.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3, vue.toDisplayString(error.value), 1)) : (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 3 }, [
415
- navigating.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4)) : vue.createCommentVNode("", true),
446
+ ])) : error.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$1, vue.toDisplayString(error.value), 1)) : (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 3 }, [
447
+ navigating.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$1)) : vue.createCommentVNode("", true),
416
448
  vue.createVNode(vue.unref(PageRenderer), { blocks: blocks.value }, null, 8, ["blocks"])
417
449
  ], 64)),
418
450
  vue.unref(adminConfig) ? (vue.openBlock(), vue.createBlock(_sfc_main$3, {
@@ -424,6 +456,111 @@ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
424
456
  };
425
457
  }
426
458
  });
459
+ const BLOX_DATA_WINDOW_KEY = "__BLOX_DATA__";
460
+ const BLOX_DATA_KEY = Symbol("blox-data");
461
+ function provideBloxData(app, opts = {}) {
462
+ const isServer = opts.server ?? false;
463
+ const payload = isServer ? null : readPayload();
464
+ const registry2 = { ssr: /* @__PURE__ */ new Map(), payload, isServer, seo: {}, seoSources: [] };
465
+ app.provide(BLOX_DATA_KEY, registry2);
466
+ globalThis.__BLOX_DATA_REGISTRY__ = registry2;
467
+ return registry2;
468
+ }
469
+ function readPayload() {
470
+ if (typeof window === "undefined") return null;
471
+ const raw = window[BLOX_DATA_WINDOW_KEY];
472
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
473
+ return raw;
474
+ }
475
+ return null;
476
+ }
477
+ function getRegistry() {
478
+ if (vue.getCurrentInstance()) {
479
+ const injected = vue.inject(BLOX_DATA_KEY, null);
480
+ if (injected) return injected;
481
+ }
482
+ return globalThis.__BLOX_DATA_REGISTRY__ ?? null;
483
+ }
484
+ function getRegistryData() {
485
+ return getRegistry();
486
+ }
487
+ function collectBloxData(registry2) {
488
+ return Object.fromEntries(registry2.ssr);
489
+ }
490
+ function useSeo(source) {
491
+ const registry2 = getRegistry();
492
+ if (registry2 == null ? void 0 : registry2.isServer) {
493
+ registry2.seoSources.push(source);
494
+ return;
495
+ }
496
+ if (vue.getCurrentInstance()) {
497
+ vue.watch(source, (v) => {
498
+ if ((v == null ? void 0 : v.title) && typeof document !== "undefined") document.title = v.title;
499
+ }, { immediate: true });
500
+ }
501
+ }
502
+ function collectBloxSeo(registry2) {
503
+ for (const source of registry2.seoSources) {
504
+ const v = source();
505
+ if (!v) continue;
506
+ if (v.title) registry2.seo.title = v.title;
507
+ if (v.description) registry2.seo.description = v.description;
508
+ if (v.image) registry2.seo.image = v.image;
509
+ if (v.alternates && Object.keys(v.alternates).length) registry2.seo.alternates = v.alternates;
510
+ }
511
+ return registry2.seo;
512
+ }
513
+ function useData(key, fetcher, options) {
514
+ const registry2 = getRegistry();
515
+ const data = vue.shallowRef(options.default);
516
+ const pending = vue.ref(false);
517
+ const error = vue.ref(null);
518
+ const currentKey = () => vue.toValue(key);
519
+ const initialKey = currentKey();
520
+ if ((registry2 == null ? void 0 : registry2.payload) && initialKey in registry2.payload) {
521
+ data.value = registry2.payload[initialKey];
522
+ watchKey(initialKey);
523
+ return { data, pending, error, refresh };
524
+ }
525
+ if ((registry2 == null ? void 0 : registry2.isServer) && options.server !== false) {
526
+ vue.onServerPrefetch(async () => {
527
+ try {
528
+ const value = await fetcher();
529
+ data.value = value;
530
+ registry2.ssr.set(currentKey(), value);
531
+ } catch (e) {
532
+ error.value = e;
533
+ registry2.ssr.set(currentKey(), options.default);
534
+ }
535
+ });
536
+ return { data, pending, error, refresh };
537
+ }
538
+ void refresh();
539
+ watchKey(null);
540
+ return { data, pending, error, refresh };
541
+ function watchKey(skipInitial) {
542
+ if ((registry2 == null ? void 0 : registry2.isServer) || !vue.getCurrentInstance()) return;
543
+ vue.watch(currentKey, (k) => {
544
+ if (k === skipInitial) return;
545
+ if ((registry2 == null ? void 0 : registry2.payload) && k in registry2.payload) {
546
+ data.value = registry2.payload[k];
547
+ return;
548
+ }
549
+ void refresh();
550
+ });
551
+ }
552
+ async function refresh() {
553
+ pending.value = true;
554
+ error.value = null;
555
+ try {
556
+ data.value = await fetcher();
557
+ } catch (e) {
558
+ error.value = e;
559
+ } finally {
560
+ pending.value = false;
561
+ }
562
+ }
563
+ }
427
564
  function normalizeLink(href) {
428
565
  const v = href == null ? void 0 : href.trim();
429
566
  if (!v) return void 0;
@@ -510,198 +647,6 @@ function installSmartLinks(router) {
510
647
  document.addEventListener("click", onClick);
511
648
  return () => document.removeEventListener("click", onClick);
512
649
  }
513
- function isServer() {
514
- try {
515
- if (false) ;
516
- } catch {
517
- }
518
- return typeof window === "undefined";
519
- }
520
- function readPayload() {
521
- const root = typeof window !== "undefined" ? window : globalThis;
522
- const existing = root[ssg_client.BLOX_DATA_WINDOW_KEY];
523
- if (existing && typeof existing === "object" && !Array.isArray(existing)) {
524
- return existing;
525
- }
526
- const fresh = {};
527
- root[ssg_client.BLOX_DATA_WINDOW_KEY] = fresh;
528
- return fresh;
529
- }
530
- function resolveDefault(opts) {
531
- if (typeof opts.default === "function") return opts.default();
532
- return opts.default;
533
- }
534
- function useData(key, handler, opts = {}) {
535
- const data = vue.ref(resolveDefault(opts));
536
- const pending = vue.ref(false);
537
- const error = vue.ref(null);
538
- async function refresh() {
539
- const k = vue.toValue(key);
540
- pending.value = true;
541
- error.value = null;
542
- try {
543
- const result = await handler();
544
- data.value = result;
545
- readPayload()[k] = result;
546
- } catch (e) {
547
- error.value = e instanceof Error ? e : new Error(String(e));
548
- } finally {
549
- pending.value = false;
550
- }
551
- }
552
- function hydrateFromPayload() {
553
- const k = vue.toValue(key);
554
- const payload = readPayload();
555
- if (!Object.prototype.hasOwnProperty.call(payload, k)) return false;
556
- data.value = payload[k];
557
- return true;
558
- }
559
- if (isServer()) {
560
- vue.onServerPrefetch(() => refresh());
561
- } else if (!hydrateFromPayload()) {
562
- void refresh();
563
- }
564
- vue.watch(() => vue.toValue(key), () => {
565
- if (!hydrateFromPayload()) void refresh();
566
- });
567
- return { data, pending, error, refresh };
568
- }
569
- function withLocaleRoutes(path, component, locales, defaultLocale) {
570
- const normalized = path.startsWith("/") ? path : `/${path}`;
571
- const others = locales.filter((l) => l && l !== defaultLocale);
572
- const localePattern = others.join("|");
573
- const routes = [
574
- { path: normalized, component }
575
- ];
576
- if (localePattern) {
577
- routes.push({
578
- path: `/:locale(${localePattern})${normalized}`,
579
- component
580
- });
581
- }
582
- return routes;
583
- }
584
- const _hoisted_1$1 = ["href"];
585
- const _hoisted_2 = ["href"];
586
- const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
587
- ...{ inheritAttrs: false },
588
- __name: "LocaleRouterLink",
589
- props: {
590
- to: {},
591
- replace: { type: Boolean },
592
- activeClass: {},
593
- exactActiveClass: {},
594
- ariaCurrentValue: {}
595
- },
596
- setup(__props) {
597
- const props = __props;
598
- const attrs = vue.useAttrs();
599
- const strategy = vue.inject(BLOX_LOCALE_STRATEGY_KEY, null);
600
- const { locale: locale2 } = useLocale();
601
- const resolved = vue.computed(() => {
602
- if (typeof props.to !== "string") {
603
- return { kind: "route", to: props.to };
604
- }
605
- const href = normalizeLink(props.to) ?? props.to.trim();
606
- const kind = classifyLink(href);
607
- if (kind === "external") return { kind: "external", href };
608
- if (kind === "special") return { kind: "special", href };
609
- const path = toInternalPath(href);
610
- const loc = String(locale2.value || "").slice(0, 2).toLowerCase();
611
- const to = strategy ? strategy.toPath(path, loc || void 0) : path;
612
- return { kind: "route", to };
613
- });
614
- return (_ctx, _cache) => {
615
- return resolved.value.kind === "external" ? (vue.openBlock(), vue.createElementBlock("a", vue.mergeProps({ key: 0 }, vue.unref(attrs), {
616
- href: resolved.value.href,
617
- target: "_blank",
618
- rel: "noopener noreferrer"
619
- }), [
620
- vue.renderSlot(_ctx.$slots, "default")
621
- ], 16, _hoisted_1$1)) : resolved.value.kind === "special" ? (vue.openBlock(), vue.createElementBlock("a", vue.mergeProps({ key: 1 }, vue.unref(attrs), {
622
- href: resolved.value.href
623
- }), [
624
- vue.renderSlot(_ctx.$slots, "default")
625
- ], 16, _hoisted_2)) : (vue.openBlock(), vue.createBlock(vue.unref(vueRouter.RouterLink), vue.normalizeProps(vue.mergeProps({ key: 2 }, { ...props, ...vue.unref(attrs), to: resolved.value.to })), {
626
- default: vue.withCtx(() => [
627
- vue.renderSlot(_ctx.$slots, "default")
628
- ]),
629
- _: 3
630
- }, 16));
631
- };
632
- }
633
- });
634
- const BLOX_CONTENT_ITEM_KEY = Symbol("blox-content-item");
635
- function useContentItem() {
636
- return vue.inject(BLOX_CONTENT_ITEM_KEY, null) ?? vue.ref(null);
637
- }
638
- const _hoisted_1 = {
639
- key: 1,
640
- class: "blox-content-detail"
641
- };
642
- const _sfc_main = /* @__PURE__ */ vue.defineComponent({
643
- __name: "ContentDetailHost",
644
- setup(__props) {
645
- const route = vueRouter.useRoute();
646
- const { locale: locale2 } = useLocale();
647
- const def = vue.computed(() => route.meta.contentDef);
648
- const slug = vue.computed(() => String(route.params.slug ?? ""));
649
- const { data: item } = useData(
650
- () => {
651
- var _a;
652
- return `content:${((_a = def.value) == null ? void 0 : _a.collection) ?? ""}:${slug.value}:${locale2.value}`;
653
- },
654
- async () => {
655
- var _a, _b;
656
- const collection = (_a = def.value) == null ? void 0 : _a.collection;
657
- const s = slug.value;
658
- if (!collection || !s) return null;
659
- const escaped = s.replace(/"/g, '\\"');
660
- const page = await listItems(collection, {
661
- locale: locale2.value,
662
- q: `slug eq "${escaped}"`,
663
- limit: 1
664
- });
665
- return ((_b = page.items) == null ? void 0 : _b[0]) ?? null;
666
- },
667
- { default: null }
668
- );
669
- vue.provide(BLOX_CONTENT_ITEM_KEY, item);
670
- const Detail = vue.computed(() => {
671
- var _a;
672
- return (_a = def.value) == null ? void 0 : _a.component;
673
- });
674
- return (_ctx, _cache) => {
675
- return Detail.value ? (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(Detail.value), { key: 0 })) : vue.unref(item) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
676
- vue.createElementVNode("pre", null, vue.toDisplayString(vue.unref(item)), 1)
677
- ])) : vue.createCommentVNode("", true);
678
- };
679
- }
680
- });
681
- const registry = [];
682
- function defineContent(defs) {
683
- registry.length = 0;
684
- registry.push(...defs);
685
- }
686
- function contentRoutes() {
687
- return registry;
688
- }
689
- function registerContentRoutesOnRouter(router, locales, defaultLocale) {
690
- for (const def of registry) {
691
- const routes = withLocaleRoutes(def.route, _sfc_main, locales, defaultLocale);
692
- routes.forEach((r, i) => {
693
- router.addRoute({
694
- ...r,
695
- // Only the default-locale path gets the stable name.
696
- name: i === 0 ? def.name : void 0,
697
- meta: {
698
- ...r.meta ?? {},
699
- contentDef: def
700
- }
701
- });
702
- });
703
- }
704
- }
705
650
  function createPathStrategy(options) {
706
651
  const { defaultLocale, supportedLocales } = options;
707
652
  let _currentLocale = defaultLocale;
@@ -731,10 +676,7 @@ function createPathStrategy(options) {
731
676
  },
732
677
  toPath(slug, locale2) {
733
678
  const loc = locale2 || _currentLocale;
734
- let s = slug || "/";
735
- if (s && !s.startsWith("/") && !/^(https?:|mailto:|tel:|sms:|whatsapp:|geo:|#|\/\/)/i.test(s)) {
736
- s = `/${s}`;
737
- }
679
+ let s = slug ? slug.startsWith("/") ? slug : `/${slug}` : "/";
738
680
  const segments = s.replace(/^\//, "").split("/").filter(Boolean);
739
681
  if (segments[0] && supportedLocales.includes(segments[0])) {
740
682
  const rest = segments.slice(1).join("/");
@@ -756,6 +698,18 @@ function createPathStrategy(options) {
756
698
  })();
757
699
  const target = locale2 === defaultLocale ? bare : bare === "/" ? `/${locale2}` : `/${locale2}${bare}`;
758
700
  router.push(target);
701
+ },
702
+ normalize(path, intendedLocale) {
703
+ const p = path || "/";
704
+ const [pathname, ...restQ] = p.split(/(?=[?#])/);
705
+ const suffix = restQ.join("");
706
+ const segments = (pathname || "/").replace(/^\//, "").split("/").filter(Boolean);
707
+ const first = segments[0];
708
+ if (first && supportedLocales.includes(first)) return null;
709
+ if (intendedLocale === defaultLocale) return null;
710
+ const bare = segments.length ? `/${segments.join("/")}` : "/";
711
+ const rebuilt = bare === "/" ? `/${intendedLocale}` : `/${intendedLocale}${bare}`;
712
+ return `${rebuilt}${suffix}`;
759
713
  }
760
714
  };
761
715
  }
@@ -790,6 +744,9 @@ function createDomainStrategy(options) {
790
744
  const { protocol } = window.location;
791
745
  const s = slug || "/";
792
746
  window.location.href = `${protocol}//${domain}${s}`;
747
+ },
748
+ normalize() {
749
+ return null;
793
750
  }
794
751
  };
795
752
  }
@@ -826,6 +783,10 @@ class BloxInstance {
826
783
  this._strategy = createLocaleStrategy(options ?? {});
827
784
  this._adminEdit = options == null ? void 0 : options.adminEdit;
828
785
  }
786
+ /** The active locale strategy (path/domain). Used by the nav guard. */
787
+ get strategy() {
788
+ return this._strategy;
789
+ }
829
790
  registerModules(modules) {
830
791
  const list = Array.isArray(modules) ? modules : Object.values(modules);
831
792
  for (const mod of list) {
@@ -899,14 +860,9 @@ class BloxInstance {
899
860
  }
900
861
  router.addRoute({
901
862
  path: "/_blox_preview",
902
- component: () => Promise.resolve().then(() => require("./PreviewApp-B8EmNfyH.cjs")),
863
+ component: () => Promise.resolve().then(() => require("./PreviewApp-APyemzqx.cjs")),
903
864
  beforeEnter: () => window.parent !== window ? true : "/"
904
865
  });
905
- registerContentRoutesOnRouter(
906
- router,
907
- this._config.supportedLocales,
908
- this._config.defaultLocale
909
- );
910
866
  router.addRoute({ path: "/:pathMatch(.*)*", component: _sfc_main$2 });
911
867
  this._routeRegistered = true;
912
868
  return this;
@@ -938,7 +894,6 @@ class BloxInstance {
938
894
  app.provide(BLOX_CONFIG_KEY, this._config);
939
895
  app.provide(BLOX_LOCALE_STRATEGY_KEY, this._strategy);
940
896
  if (this._adminEdit) app.provide(BLOX_ADMIN_CONFIG_KEY, this._adminEdit);
941
- app._context.components.RouterLink = _sfc_main$1;
942
897
  }
943
898
  }
944
899
  function isBlockDefinition(value) {
@@ -954,9 +909,234 @@ function createBlox(options) {
954
909
  if (options == null ? void 0 : options.router) instance.registerRoutes(options.router);
955
910
  return instance;
956
911
  }
912
+ const registry = /* @__PURE__ */ new Map();
913
+ function paramsOf(route) {
914
+ return [...route.matchAll(/:([A-Za-z0-9_]+)/g)].map((m) => m[1]);
915
+ }
916
+ function defineContent(inputs) {
917
+ for (const input of inputs) {
918
+ const params = paramsOf(input.route);
919
+ if (!params.includes("slug")) {
920
+ throw new Error(`[blox/content] route "${input.route}" for "${input.name}" must contain a :slug param`);
921
+ }
922
+ registry.set(input.name, {
923
+ name: input.name,
924
+ collection: input.collection,
925
+ route: input.route,
926
+ component: input.component,
927
+ view: input.view,
928
+ params
929
+ });
930
+ }
931
+ }
932
+ function contentRoutes() {
933
+ return [...registry.values()];
934
+ }
935
+ function getContentRoute(name) {
936
+ return registry.get(name);
937
+ }
938
+ function getContentRouteByCollection(collection) {
939
+ for (const r of registry.values()) if (r.collection === collection) return r;
940
+ return void 0;
941
+ }
942
+ const CONTENT_ITEM_CTX = Symbol("blox:content-item-ctx");
943
+ function useContentItem(collectionArg, slugArg) {
944
+ const { locale: locale2 } = useLocale();
945
+ const ctx = vue.inject(CONTENT_ITEM_CTX, null);
946
+ const route = safeRoute();
947
+ const coll = () => {
948
+ var _a, _b;
949
+ if (collectionArg != null) return String(vue.toValue(collectionArg) || "");
950
+ if (ctx) return String(vue.toValue(ctx.collection) || "");
951
+ const name = (_a = route == null ? void 0 : route.meta) == null ? void 0 : _a.content;
952
+ return name ? ((_b = getContentRoute(name)) == null ? void 0 : _b.collection) ?? "" : "";
953
+ };
954
+ const slg = () => {
955
+ var _a;
956
+ if (slugArg != null) return String(vue.toValue(slugArg) || "");
957
+ if (ctx) return String(vue.toValue(ctx.slug) || "");
958
+ return String(((_a = route == null ? void 0 : route.params) == null ? void 0 : _a.slug) ?? "");
959
+ };
960
+ const loc = () => String(locale2.value || "en").slice(0, 2).toLowerCase();
961
+ const { data } = useData(
962
+ () => `content:${coll()}:${slg()}:${loc()}`,
963
+ async () => {
964
+ const c = coll();
965
+ const s = slg();
966
+ if (!c || !s) return null;
967
+ const res = await listItems(c, { locale: loc(), limit: 1e3 });
968
+ const items = Array.isArray(res) ? res : (res == null ? void 0 : res.items) ?? [];
969
+ return items.find((it) => String((it == null ? void 0 : it.slug) ?? "") === s) ?? null;
970
+ },
971
+ { default: null }
972
+ );
973
+ return data;
974
+ }
975
+ function provideContentItem(collection, slug) {
976
+ vue.provide(CONTENT_ITEM_CTX, { collection, slug });
977
+ }
978
+ function safeRoute() {
979
+ try {
980
+ return vueRouter.useRoute();
981
+ } catch {
982
+ return null;
983
+ }
984
+ }
985
+ const _hoisted_1 = {
986
+ key: 0,
987
+ class: "blox-content-detail"
988
+ };
989
+ const _hoisted_2 = ["src", "alt"];
990
+ const _hoisted_3 = {
991
+ key: 1,
992
+ class: "blox-content-detail__title"
993
+ };
994
+ const _hoisted_4 = ["innerHTML"];
995
+ const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
996
+ __name: "ContentDetailView",
997
+ setup(__props) {
998
+ const route = vueRouter.useRoute();
999
+ const item = useContentItem();
1000
+ const schema = vue.computed(() => {
1001
+ var _a, _b;
1002
+ const name = (_a = route.meta) == null ? void 0 : _a.content;
1003
+ return (name ? (_b = getContentRoute(name)) == null ? void 0 : _b.view : void 0) ?? {};
1004
+ });
1005
+ function field(key) {
1006
+ if (!key || !item.value) return "";
1007
+ return String(item.value[key] ?? "");
1008
+ }
1009
+ const title = vue.computed(() => field(schema.value.title));
1010
+ const body = vue.computed(() => field(schema.value.body));
1011
+ const description = vue.computed(() => {
1012
+ const raw = field(schema.value.description) || body.value;
1013
+ return raw.replace(/<[^>]*>/g, "").replace(/\s+/g, " ").trim().slice(0, 160);
1014
+ });
1015
+ const image = vue.computed(() => {
1016
+ var _a;
1017
+ const v = schema.value.image ? (_a = item.value) == null ? void 0 : _a[schema.value.image] : void 0;
1018
+ if (!v) return "";
1019
+ return typeof v === "object" ? v.imageURL ?? "" : String(v);
1020
+ });
1021
+ useSeo(() => {
1022
+ if (!item.value) return null;
1023
+ return { title: title.value, description: description.value, image: image.value };
1024
+ });
1025
+ return (_ctx, _cache) => {
1026
+ return vue.unref(item) ? (vue.openBlock(), vue.createElementBlock("article", _hoisted_1, [
1027
+ image.value ? (vue.openBlock(), vue.createElementBlock("img", {
1028
+ key: 0,
1029
+ class: "blox-content-detail__image",
1030
+ src: image.value,
1031
+ alt: title.value
1032
+ }, null, 8, _hoisted_2)) : vue.createCommentVNode("", true),
1033
+ title.value ? (vue.openBlock(), vue.createElementBlock("h1", _hoisted_3, vue.toDisplayString(title.value), 1)) : vue.createCommentVNode("", true),
1034
+ body.value ? (vue.openBlock(), vue.createElementBlock("div", {
1035
+ key: 2,
1036
+ class: "blox-content-detail__body",
1037
+ innerHTML: body.value
1038
+ }, null, 8, _hoisted_4)) : vue.createCommentVNode("", true)
1039
+ ])) : vue.createCommentVNode("", true);
1040
+ };
1041
+ }
1042
+ });
1043
+ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
1044
+ __name: "ContentHost",
1045
+ setup(__props) {
1046
+ var _a;
1047
+ const route = vueRouter.useRoute();
1048
+ const name = (_a = route.meta) == null ? void 0 : _a.content;
1049
+ const registration = name ? getContentRoute(name) : void 0;
1050
+ const component = vue.markRaw((registration == null ? void 0 : registration.component) ?? _sfc_main$1);
1051
+ provideContentItem(
1052
+ () => (registration == null ? void 0 : registration.collection) ?? "",
1053
+ () => String(route.params.slug ?? "")
1054
+ );
1055
+ return (_ctx, _cache) => {
1056
+ return vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(vue.unref(component)), {
1057
+ key: vue.unref(route).fullPath
1058
+ });
1059
+ };
1060
+ }
1061
+ });
1062
+ function generateContentRoutes(supportedLocales, defaultLocale) {
1063
+ const records = [];
1064
+ for (const route of contentRoutes()) {
1065
+ const bare = route.route.startsWith("/") ? route.route : `/${route.route}`;
1066
+ records.push({
1067
+ path: bare,
1068
+ name: route.name,
1069
+ component: _sfc_main,
1070
+ meta: { content: route.name }
1071
+ });
1072
+ for (const loc of supportedLocales) {
1073
+ if (loc === defaultLocale) continue;
1074
+ records.push({
1075
+ path: `/${loc}${bare}`,
1076
+ name: `${route.name}:${loc}`,
1077
+ component: _sfc_main,
1078
+ meta: { content: route.name }
1079
+ });
1080
+ }
1081
+ }
1082
+ return records;
1083
+ }
1084
+ function installLocaleAwareResolve(router, strategy) {
1085
+ const { locale: locale2 } = useLocale();
1086
+ const supported = strategy.locales;
1087
+ const defaultLocale = strategy.defaultLocale;
1088
+ const activeLocale = () => String(locale2.value || "").slice(0, 2).toLowerCase() || defaultLocale;
1089
+ const originalResolve = router.resolve.bind(router);
1090
+ router.resolve = (to, currentLocation) => {
1091
+ if (typeof to === "string") {
1092
+ const href = normalizeLink(to) ?? to;
1093
+ if (classifyLink(href) === "internal") {
1094
+ to = strategy.toPath(href, activeLocale());
1095
+ }
1096
+ } else if (to && typeof to === "object" && typeof to.name === "string") {
1097
+ const base = to.name.split(":")[0];
1098
+ if (getContentRoute(base) && supported.length) {
1099
+ const loc = activeLocale();
1100
+ const name = loc && loc !== defaultLocale ? `${base}:${loc}` : base;
1101
+ if (router.hasRoute(name)) to = { ...to, name };
1102
+ }
1103
+ }
1104
+ return originalResolve(to, currentLocation);
1105
+ };
1106
+ }
1107
+ function installContentFallback(router, supportedLocales, defaultLocale) {
1108
+ const localeOf = (path) => {
1109
+ const first = path.replace(/^\//, "").split("/")[0];
1110
+ return first && supportedLocales.includes(first) ? first : defaultLocale;
1111
+ };
1112
+ router.beforeResolve(async (to) => {
1113
+ var _a;
1114
+ const name = (_a = to.meta) == null ? void 0 : _a.content;
1115
+ if (!name) return true;
1116
+ const registration = getContentRoute(name);
1117
+ if (!registration) return true;
1118
+ const slug = String(to.params.slug ?? "");
1119
+ if (!slug) return true;
1120
+ const urlLocale = localeOf(to.path);
1121
+ const here = await getItemBySlug(registration.collection, slug, urlLocale).catch(() => null);
1122
+ if (here) return true;
1123
+ const probe = await getItemBySlug(registration.collection, slug).catch(() => null);
1124
+ const available = Array.isArray(probe == null ? void 0 : probe.available_locales) ? probe.available_locales : [];
1125
+ const target = [defaultLocale, ...supportedLocales].find(
1126
+ (l) => l !== urlLocale && available.includes(l)
1127
+ );
1128
+ if (!target || !probe) return true;
1129
+ const targetItem = await getItemBySlug(registration.collection, slug, target).catch(() => null);
1130
+ const targetSlug = String((targetItem == null ? void 0 : targetItem.slug) ?? slug);
1131
+ const barePath = registration.route.replace(/:slug(?=\/|$)/, targetSlug);
1132
+ const redirect = target === defaultLocale ? barePath : `/${target}${barePath}`;
1133
+ return redirect;
1134
+ });
1135
+ }
957
1136
  exports.BLOX_ADMIN_CONFIG_KEY = BLOX_ADMIN_CONFIG_KEY;
958
1137
  exports.BLOX_CONFIG_KEY = BLOX_CONFIG_KEY;
959
- exports.BLOX_CONTENT_ITEM_KEY = BLOX_CONTENT_ITEM_KEY;
1138
+ exports.BLOX_DATA_KEY = BLOX_DATA_KEY;
1139
+ exports.BLOX_DATA_WINDOW_KEY = BLOX_DATA_WINDOW_KEY;
960
1140
  exports.BLOX_GLOBAL_RESOLVER_KEY = BLOX_GLOBAL_RESOLVER_KEY;
961
1141
  exports.BLOX_LOCALE_STRATEGY_KEY = BLOX_LOCALE_STRATEGY_KEY;
962
1142
  exports.BLOX_REGISTRY_KEY = BLOX_REGISTRY_KEY;
@@ -967,24 +1147,39 @@ exports.PageRenderer = PageRenderer;
967
1147
  exports._sfc_main = _sfc_main$3;
968
1148
  exports._sfc_main$1 = _sfc_main$2;
969
1149
  exports._sfc_main$2 = _sfc_main$1;
1150
+ exports._sfc_main$3 = _sfc_main;
970
1151
  exports.classifyLink = classifyLink;
1152
+ exports.collectBloxData = collectBloxData;
1153
+ exports.collectBloxSeo = collectBloxSeo;
971
1154
  exports.configureApi = configureApi;
972
1155
  exports.contentRoutes = contentRoutes;
973
1156
  exports.createBlox = createBlox;
974
1157
  exports.defineContent = defineContent;
1158
+ exports.generateContentRoutes = generateContentRoutes;
1159
+ exports.getContentRoute = getContentRoute;
1160
+ exports.getContentRouteByCollection = getContentRouteByCollection;
1161
+ exports.getItemById = getItemById;
1162
+ exports.getItemBySlug = getItemBySlug;
1163
+ exports.getRegistryData = getRegistryData;
975
1164
  exports.getWebsiteId = getWebsiteId;
976
1165
  exports.getWebsiteIdSync = getWebsiteIdSync;
977
1166
  exports.globalRefOf = globalRefOf;
1167
+ exports.installContentFallback = installContentFallback;
1168
+ exports.installLocaleAwareResolve = installLocaleAwareResolve;
978
1169
  exports.installSmartLinks = installSmartLinks;
979
1170
  exports.isAbsoluteExternal = isAbsoluteExternal;
980
1171
  exports.isSpecialScheme = isSpecialScheme;
981
1172
  exports.listItems = listItems;
982
1173
  exports.normalizeLink = normalizeLink;
983
1174
  exports.normalizeTo = normalizeTo;
1175
+ exports.provideBloxData = provideBloxData;
1176
+ exports.provideContentItem = provideContentItem;
984
1177
  exports.resolvePath = resolvePath;
1178
+ exports.setActiveLocale = setActiveLocale;
1179
+ exports.setApiOrigin = setApiOrigin;
985
1180
  exports.toInternalPath = toInternalPath;
986
1181
  exports.useBloxEdit = useBloxEdit;
987
1182
  exports.useContentItem = useContentItem;
988
1183
  exports.useData = useData;
989
1184
  exports.useLocale = useLocale;
990
- exports.withLocaleRoutes = withLocaleRoutes;
1185
+ exports.useSeo = useSeo;